diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2007-12-11 15:16:51 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2007-12-11 15:16:51 +0000 |
commit | 7d23cd1b3124a597be3bfdf1fd82816daee0b5c4 (patch) | |
tree | 170677c8f2591a531db76375fe48249bafe102e8 /libs/rubberband | |
parent | 8037a26395b0c7cb68b1fc33fb93d2e86738ede4 (diff) |
pulling vendor branch for rubberband
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2768 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/rubberband')
47 files changed, 15845 insertions, 0 deletions
diff --git a/libs/rubberband/1.0/COPYING b/libs/rubberband/1.0/COPYING new file mode 100644 index 0000000000..c7aea1896f --- /dev/null +++ b/libs/rubberband/1.0/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, 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 diff --git a/libs/rubberband/1.0/Makefile.in b/libs/rubberband/1.0/Makefile.in new file mode 100644 index 0000000000..9d4666ffaf --- /dev/null +++ b/libs/rubberband/1.0/Makefile.in @@ -0,0 +1,189 @@ + +CXX := @CXX@ +CXXFLAGS := -DUSE_PTHREADS -DHAVE_LIBSAMPLERATE -DHAVE_FFTW3 -DFFTW_DOUBLE_ONLY @CXXFLAGS@ @SRC_CFLAGS@ @SNDFILE_CFLAGS@ @FFTW_CFLAGS@ @Vamp_CFLAGS@ -Irubberband -Isrc $(OPTFLAGS) +LDFLAGS := @LDFLAGS@ -lpthread $(LDFLAGS) + +LIBRARY_LIBS := @SRC_LIBS@ @FFTW_LIBS@ +PROGRAM_LIBS := @SNDFILE_LIBS@ $(LIBRARY_LIBS) +VAMP_PLUGIN_LIBS := @Vamp_LIBS@ $(LIBRARY_LIBS) +LADSPA_PLUGIN_LIBS := $(LIBRARY_LIBS) + +MKDIR := mkdir +AR := ar + +DYNAMIC_LDFLAGS := -shared -Wl,-Bsymbolic +DYNAMIC_EXTENSION := .so + +PROGRAM_TARGET := bin/rubberband +STATIC_TARGET := lib/librubberband.a +DYNAMIC_TARGET := lib/librubberband$(DYNAMIC_EXTENSION) +VAMP_TARGET := lib/vamp-rubberband$(DYNAMIC_EXTENSION) +LADSPA_TARGET := lib/ladspa-rubberband$(DYNAMIC_EXTENSION) + +INSTALL_BINDIR := @prefix@/bin +INSTALL_INCDIR := @prefix@/include/rubberband +INSTALL_LIBDIR := @prefix@/lib +INSTALL_VAMPDIR := @prefix@/lib/vamp +INSTALL_LADSPADIR := @prefix@/lib/ladspa +INSTALL_PKGDIR := @prefix@/lib/pkgconfig + +all: bin lib $(PROGRAM_TARGET) $(STATIC_TARGET) $(DYNAMIC_TARGET) $(VAMP_TARGET) $(LADSPA_TARGET) + +PUBLIC_INCLUDES := \ + rubberband/TimeStretcher.h \ + rubberband/RubberBandStretcher.h + +LIBRARY_INCLUDES := \ + src/AudioCurve.h \ + src/ConstantAudioCurve.h \ + src/FFT.h \ + src/HighFrequencyAudioCurve.h \ + src/PercussiveAudioCurve.h \ + src/Resampler.h \ + src/RingBuffer.h \ + src/Scavenger.h \ + src/SpectralDifferenceAudioCurve.h \ + src/StretchCalculator.h \ + src/StretcherImpl.h \ + src/StretcherChannelData.h \ + src/Thread.h \ + src/Window.h \ + src/sysutils.h + +LIBRARY_SOURCES := \ + src/RubberBandStretcher.cpp \ + src/ConstantAudioCurve.cpp \ + src/HighFrequencyAudioCurve.cpp \ + src/PercussiveAudioCurve.cpp \ + src/AudioCurve.cpp \ + src/Resampler.cpp \ + src/SpectralDifferenceAudioCurve.cpp \ + src/StretchCalculator.cpp \ + src/StretcherImpl.cpp \ + src/StretcherProcess.cpp \ + src/StretcherChannelData.cpp \ + src/FFT.cpp \ + src/Thread.cpp \ + src/sysutils.cpp + +PROGRAM_SOURCES := \ + src/main.cpp + +VAMP_HEADERS := \ + src/vamp/RubberBandVampPlugin.h + +VAMP_SOURCES := \ + src/vamp/RubberBandVampPlugin.cpp \ + src/vamp/libmain.cpp + +LADSPA_HEADERS := \ + src/ladspa/RubberBandPitchShifter.h + +LADSPA_SOURCES := \ + src/ladspa/RubberBandPitchShifter.cpp \ + src/ladspa/libmain.cpp + +LIBRARY_OBJECTS := $(LIBRARY_SOURCES:.cpp=.o) +PROGRAM_OBJECTS := $(PROGRAM_SOURCES:.cpp=.o) +VAMP_OBJECTS := $(VAMP_SOURCES:.cpp=.o) +LADSPA_OBJECTS := $(LADSPA_SOURCES:.cpp=.o) + +$(PROGRAM_TARGET): $(LIBRARY_OBJECTS) $(PROGRAM_OBJECTS) + $(CXX) -o $@ $^ $(PROGRAM_LIBS) $(PROGRAM_LIBS) $(LDFLAGS) + +$(STATIC_TARGET): $(LIBRARY_OBJECTS) + $(AR) rsc $@ $^ + +$(DYNAMIC_TARGET): $(LIBRARY_OBJECTS) + $(CXX) $(DYNAMIC_LDFLAGS) $^ -o $@ $(LIBRARY_LIBS) $(LDFLAGS) + +$(VAMP_TARGET): $(LIBRARY_OBJECTS) $(VAMP_OBJECTS) + $(CXX) $(DYNAMIC_LDFLAGS) -o $@ $^ $(VAMP_PLUGIN_LIBS) $(LDFLAGS) + +$(LADSPA_TARGET): $(LIBRARY_OBJECTS) $(LADSPA_OBJECTS) + $(CXX) $(DYNAMIC_LDFLAGS) -o $@ $^ $(LADSPA_PLUGIN_LIBS) $(LDFLAGS) + +bin: + $(MKDIR) $@ +lib: + $(MKDIR) $@ + +install: all + $(MKDIR) -p $(INSTALL_BINDIR) + $(MKDIR) -p $(INSTALL_INCDIR) + $(MKDIR) -p $(INSTALL_LIBDIR) + $(MKDIR) -p $(INSTALL_VAMPDIR) + $(MKDIR) -p $(INSTALL_LADSPADIR) + cp $(PROGRAM_TARGET) $(INSTALL_BINDIR) + cp $(PUBLIC_INCLUDES) $(INSTALL_INCDIR) + cp $(STATIC_TARGET) $(INSTALL_LIBDIR) + cp $(DYNAMIC_TARGET) $(INSTALL_LIBDIR) + cp $(VAMP_TARGET) $(INSTALL_VAMPDIR) + cp src/vamp/vamp-rubberband.cat $(INSTALL_VAMPDIR) + cp $(LADSPA_TARGET) $(INSTALL_LADSPADIR) + cp src/ladspa/ladspa-rubberband.cat $(INSTALL_LADSPADIR) + sed "s,%PREFIX%,@prefix@," rubberband.pc.in \ + > $(INSTALL_PKGDIR)/rubberband.pc + +clean: + rm -f $(LIBRARY_OBJECTS) $(PROGRAM_OBJECTS) $(LADSPA_OBJECTS) $(VAMP_OBJECTS) + +distclean: clean + rm -f $(PROGRAM_TARGET) $(STATIC_TARGET) $(DYNAMIC_TARGET) $(VAMP_TARGET) $(LADSPA_TARGET) + +# DO NOT DELETE + +src/AudioCurve.o: src/AudioCurve.h +src/ConstantAudioCurve.o: src/ConstantAudioCurve.h src/AudioCurve.h +src/FFT.o: src/FFT.h src/Thread.h +src/HighFrequencyAudioCurve.o: src/HighFrequencyAudioCurve.h src/AudioCurve.h +src/HighFrequencyAudioCurve.o: src/Window.h +src/main.o: src/sysutils.h +src/PercussiveAudioCurve.o: src/PercussiveAudioCurve.h src/AudioCurve.h +src/Resampler.o: src/Resampler.h +src/RubberBandStretcher.o: src/StretcherImpl.h src/Window.h src/Thread.h +src/RubberBandStretcher.o: src/RingBuffer.h src/Scavenger.h src/sysutils.h +src/RubberBandStretcher.o: src/FFT.h +src/SpectralDifferenceAudioCurve.o: src/SpectralDifferenceAudioCurve.h +src/SpectralDifferenceAudioCurve.o: src/AudioCurve.h src/Window.h +src/StretchCalculator.o: src/StretchCalculator.h +src/StretcherChannelData.o: src/StretcherChannelData.h src/StretcherImpl.h +src/StretcherChannelData.o: src/Window.h src/Thread.h src/RingBuffer.h +src/StretcherChannelData.o: src/Scavenger.h src/sysutils.h src/FFT.h +src/StretcherChannelData.o: src/Resampler.h +src/StretcherImpl.o: src/StretcherImpl.h src/Window.h src/Thread.h +src/StretcherImpl.o: src/RingBuffer.h src/Scavenger.h src/sysutils.h +src/StretcherImpl.o: src/FFT.h src/PercussiveAudioCurve.h src/AudioCurve.h +src/StretcherImpl.o: src/HighFrequencyAudioCurve.h +src/StretcherImpl.o: src/SpectralDifferenceAudioCurve.h +src/StretcherImpl.o: src/ConstantAudioCurve.h src/StretchCalculator.h +src/StretcherImpl.o: src/StretcherChannelData.h src/Resampler.h +src/StretcherProcess.o: src/StretcherImpl.h src/Window.h src/Thread.h +src/StretcherProcess.o: src/RingBuffer.h src/Scavenger.h src/sysutils.h +src/StretcherProcess.o: src/FFT.h src/PercussiveAudioCurve.h src/AudioCurve.h +src/StretcherProcess.o: src/HighFrequencyAudioCurve.h +src/StretcherProcess.o: src/ConstantAudioCurve.h src/StretchCalculator.h +src/StretcherProcess.o: src/StretcherChannelData.h src/Resampler.h +src/sysutils.o: src/sysutils.h +src/Thread.o: src/Thread.h +src/ConstantAudioCurve.o: src/AudioCurve.h +src/HighFrequencyAudioCurve.o: src/AudioCurve.h src/Window.h +src/PercussiveAudioCurve.o: src/AudioCurve.h +src/RingBuffer.o: src/Scavenger.h src/Thread.h src/sysutils.h +src/Scavenger.o: src/Thread.h src/sysutils.h +src/SpectralDifferenceAudioCurve.o: src/AudioCurve.h src/Window.h +src/StretcherChannelData.o: src/StretcherImpl.h src/Window.h src/Thread.h +src/StretcherChannelData.o: src/RingBuffer.h src/Scavenger.h src/sysutils.h +src/StretcherChannelData.o: src/FFT.h +src/StretcherImpl.o: src/Window.h src/Thread.h src/RingBuffer.h +src/StretcherImpl.o: src/Scavenger.h src/sysutils.h src/FFT.h +src/vamp/libmain.o: src/vamp/RubberBandVampPlugin.h +src/vamp/RubberBandVampPlugin.o: src/vamp/RubberBandVampPlugin.h +src/vamp/RubberBandVampPlugin.o: src/StretchCalculator.h +src/ladspa/libmain.o: src/ladspa/RubberBandPitchShifter.h src/RingBuffer.h +src/ladspa/libmain.o: src/Scavenger.h src/Thread.h src/sysutils.h +src/ladspa/RubberBandPitchShifter.o: src/ladspa/RubberBandPitchShifter.h +src/ladspa/RubberBandPitchShifter.o: src/RingBuffer.h src/Scavenger.h +src/ladspa/RubberBandPitchShifter.o: src/Thread.h src/sysutils.h +src/ladspa/RubberBandPitchShifter.o: src/RingBuffer.h src/Scavenger.h +src/ladspa/RubberBandPitchShifter.o: src/Thread.h src/sysutils.h diff --git a/libs/rubberband/1.0/README b/libs/rubberband/1.0/README new file mode 100644 index 0000000000..178234e9b5 --- /dev/null +++ b/libs/rubberband/1.0/README @@ -0,0 +1,158 @@ + +Rubber Band +=========== + +An audio time-stretching and pitch-shifting library and utility program. + +Copyright 2007 Chris Cannam, cannam@all-day-breakfast.com. + +Distributed under the GNU General Public License. + +Rubber Band is a library and utility program that permits you to +change the tempo and pitch of an audio recording independently of one +another. + + +Attractive features +~~~~~~~~~~~~~~~~~~~ + + * High quality results suitable for musical use + + Rubber Band is a phase-vocoder-based frequency domain time + stretcher with partial phase locking to peak frequencies and phase + resynchronisation at noisy transients. It is suitable for most + musical uses with its default settings, and has a range of options + for fine tuning. + + * Real-time capable + + In addition to the offline mode (for use in situations where all + audio data is available beforehand), Rubber Band supports a true + real-time, lock-free streaming mode, in which the time and pitch + scaling ratios may be dynamically adjusted during use. + + * Sample-accurate duration adjustment + + In offline mode, Rubber Band ensures that the output has exactly + the right number of samples for the given stretch ratio. (In + real-time mode Rubber Band aims to keep as closely as possible to + the exact ratio, although this depends on the audio material + itself.) + + * Multiprocessor/multi-core support + + Rubber Band's offline mode can take advantage of more than one + processor core if available, when processing data with two or more + audio channels. + + * No job too big, or too small + + Rubber Band is tuned so as to work well with the default settings + for any stretch ratio, from tiny deviations from the original + speed to very extreme stretches. + + * Handy utilities included + + The Rubber Band code includes a useful command-line time-stretch + and pitch shift utility (called simply rubberband), two LADSPA + pitch shifter plugins (Rubber Band Mono Pitch Shifter and Rubber + Band Stereo Pitch Shifter), and a Vamp audio analysis plugin which + may be used to inspect the stretch profile decisions Rubber Band + is taking. + + * Free Software + + Rubber Band is Free Software published under the GNU General + Public License. + + +Limitations +~~~~~~~~~~~ + + * Not especially fast + + The algorithm used by Rubber Band is very processor intensive, and + Rubber Band is not the fastest implementation on earth. + + * Not especially state of the art + + Rubber Band employs well known algorithms which work well in many + situations, but it isn't "cutting edge" in any interesting sense. + + * Relatively complex + + While the fundamental algorithms in Rubber Band are not especially + complex, the implementation is complicated by the support for + multiple processing modes, exact sample precision, threading, and + other features that add to the flexibility of the API. + + +Compiling Rubber Band +--------------------- + +Rubber Band is supplied with build scripts that have been tested on +Linux platforms. It is also possible to build Rubber Band on other +platforms, including both POSIX platforms such as OS/X and non-POSIX +platforms such as Win32. There are some example Makefiles in the misc +directory, but if you're using a proprietary platform and you get +stuck I'm afraid you're on your own, unless you want to pay us... + +To build Rubber Band you will also need libsndfile, libsamplerate, +FFTW3, the Vamp plugin SDK, the LADSPA plugin header, the pthread +library (except on Win32), and a C++ compiler. The code has been +tested with GCC 4.x and with the Intel C++ compiler. + +Rubber Band comes with a simple autoconf script. Run + + $ ./configure + $ make + +to compile, and optionally + + # make install + +to install. + + +Using the Rubber Band utility +----------------------------- + +The Rubber Band command-line utility builds as bin/rubberband. The +basic incantation is + + $ rubberband -t <timeratio> -p <pitchratio> <infile.wav> <outfile.wav> + +For example, + + $ rubberband -t 1.5 -p 2.0 test.wav output.wav + +stretches the file test.wav to 50% longer than its original duration, +shifts it up in pitch by one octave, and writes the output to output.wav. + +Several further options are available: run "rubberband -h" for help. +In particular, different types of music may benefit from different +"crispness" options (-c <n> where <n> is from 0 to 5). + + +Using the Rubber Band library +----------------------------- + +The Rubber Band library has a public API that consists of one C++ +class, called RubberBandStretcher in the RubberBand namespace. You +should #include <rubberband/RubberBandStretcher.h> to use this class. +There is extensive documentation in the class header. + +The source code for the command-line utility (src/main.cpp) provides a +good example of how to use Rubber Band in offline mode; the LADSPA +pitch shifter plugin (src/ladspa/RubberBandPitchShifter.cpp) may be +used as an example of Rubber Band in real-time mode. + +IMPORTANT: Please ensure you have read and understood the licensing +terms for Rubber Band before using it in another application. This +library is provided under the GNU General Public License, which means +that any application that uses it must also be published under the GPL +or a compatible license (i.e. with its full source code also available +for modification and redistribution). See the file COPYING for more +details. Alternative commercial and proprietary licensing terms are +available; please contact the author if you are interested. + diff --git a/libs/rubberband/1.0/configure b/libs/rubberband/1.0/configure new file mode 100755 index 0000000000..3ad36a8124 --- /dev/null +++ b/libs/rubberband/1.0/configure @@ -0,0 +1,5775 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61 for RubberBand 0.1. +# +# Report bugs to <cannam@all-day-breakfast.com>. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 </dev/null 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME='RubberBand' +PACKAGE_TARNAME='rubberband' +PACKAGE_VERSION='0.1' +PACKAGE_STRING='RubberBand 0.1' +PACKAGE_BUGREPORT='cannam@all-day-breakfast.com' + +ac_unique_file="src/StretcherImpl.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +CXX +CXXFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CXX +EXEEXT +OBJEXT +CC +CFLAGS +ac_ct_CC +CPP +GREP +EGREP +PKG_CONFIG +SRC_CFLAGS +SRC_LIBS +SNDFILE_CFLAGS +SNDFILE_LIBS +FFTW_CFLAGS +FFTW_LIBS +Vamp_CFLAGS +Vamp_LIBS +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CXX +CXXFLAGS +LDFLAGS +LIBS +CPPFLAGS +CCC +CC +CFLAGS +CPP +PKG_CONFIG +SRC_CFLAGS +SRC_LIBS +SNDFILE_CFLAGS +SNDFILE_LIBS +FFTW_CFLAGS +FFTW_LIBS +Vamp_CFLAGS +Vamp_LIBS' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures RubberBand 0.1 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/rubberband] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of RubberBand 0.1:";; + esac + cat <<\_ACEOF + +Some influential environment variables: + CXX C++ compiler command + CXXFLAGS C++ compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CC C compiler command + CFLAGS C compiler flags + CPP C preprocessor + PKG_CONFIG path to pkg-config utility + SRC_CFLAGS C compiler flags for SRC, overriding pkg-config + SRC_LIBS linker flags for SRC, overriding pkg-config + SNDFILE_CFLAGS + C compiler flags for SNDFILE, overriding pkg-config + SNDFILE_LIBS + linker flags for SNDFILE, overriding pkg-config + FFTW_CFLAGS C compiler flags for FFTW, overriding pkg-config + FFTW_LIBS linker flags for FFTW, overriding pkg-config + Vamp_CFLAGS C compiler flags for Vamp, overriding pkg-config + Vamp_LIBS linker flags for Vamp, overriding pkg-config + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to <cannam@all-day-breakfast.com>. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +RubberBand configure 0.1 +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by RubberBand $as_me 0.1, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C++ compiler default output file name" >&5 +echo $ECHO_N "checking for C++ compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C++ compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C++ compiler works" >&5 +echo $ECHO_N "checking whether the C++ compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; } +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CXXFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_GREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_GREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_EGREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_EGREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 +echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6; } +if test "${ac_cv_c_bigendian+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # See if sys/param.h defines the BYTE_ORDER macro. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <sys/types.h> +#include <sys/param.h> + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN && defined LITTLE_ENDIAN \ + && BYTE_ORDER && BIG_ENDIAN && LITTLE_ENDIAN) + bogus endian macros +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + # It does; now see whether it defined to BIG_ENDIAN or not. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <sys/types.h> +#include <sys/param.h> + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_bigendian=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_bigendian=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # It does not; compile a test program. +if test "$cross_compiling" = yes; then + # try to guess the endianness by grepping values into an object file + ac_cv_c_bigendian=unknown + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; +short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; +void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } +short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; +short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; +void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } +int +main () +{ + _ascii (); _ebcdic (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then + ac_cv_c_bigendian=yes +fi +if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=no +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 +echo "${ECHO_T}$ac_cv_c_bigendian" >&6; } +case $ac_cv_c_bigendian in + yes) + +cat >>confdefs.h <<\_ACEOF +#define WORDS_BIGENDIAN 1 +_ACEOF + ;; + no) + ;; + *) + { { echo "$as_me:$LINENO: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&5 +echo "$as_me: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} + { (exit 1); exit 1; }; } ;; +esac + + + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_PKG_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5 +echo "${ECHO_T}$PKG_CONFIG" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5 +echo "${ECHO_T}$ac_pt_PKG_CONFIG" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.9.0 + { echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5 +echo $ECHO_N "checking pkg-config is at least version $_pkg_min_version... $ECHO_C" >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + PKG_CONFIG="" + fi + +fi + +pkg_failed=no +{ echo "$as_me:$LINENO: checking for SRC" >&5 +echo $ECHO_N "checking for SRC... $ECHO_C" >&6; } + +if test -n "$PKG_CONFIG"; then + if test -n "$SRC_CFLAGS"; then + pkg_cv_SRC_CFLAGS="$SRC_CFLAGS" + else + if test -n "$PKG_CONFIG" && \ + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"samplerate\"") >&5 + ($PKG_CONFIG --exists --print-errors "samplerate") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + pkg_cv_SRC_CFLAGS=`$PKG_CONFIG --cflags "samplerate" 2>/dev/null` +else + pkg_failed=yes +fi + fi +else + pkg_failed=untried +fi +if test -n "$PKG_CONFIG"; then + if test -n "$SRC_LIBS"; then + pkg_cv_SRC_LIBS="$SRC_LIBS" + else + if test -n "$PKG_CONFIG" && \ + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"samplerate\"") >&5 + ($PKG_CONFIG --exists --print-errors "samplerate") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + pkg_cv_SRC_LIBS=`$PKG_CONFIG --libs "samplerate" 2>/dev/null` +else + pkg_failed=yes +fi + fi +else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + SRC_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "samplerate"` + else + SRC_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "samplerate"` + fi + # Put the nasty error message in config.log where it belongs + echo "$SRC_PKG_ERRORS" >&5 + + { { echo "$as_me:$LINENO: error: Package requirements (samplerate) were not met: + +$SRC_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables SRC_CFLAGS +and SRC_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. +" >&5 +echo "$as_me: error: Package requirements (samplerate) were not met: + +$SRC_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables SRC_CFLAGS +and SRC_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. +" >&2;} + { (exit 1); exit 1; }; } +elif test $pkg_failed = untried; then + { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables SRC_CFLAGS +and SRC_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See \`config.log' for more details." >&5 +echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables SRC_CFLAGS +and SRC_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +else + SRC_CFLAGS=$pkg_cv_SRC_CFLAGS + SRC_LIBS=$pkg_cv_SRC_LIBS + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + : +fi + + + + +pkg_failed=no +{ echo "$as_me:$LINENO: checking for SNDFILE" >&5 +echo $ECHO_N "checking for SNDFILE... $ECHO_C" >&6; } + +if test -n "$PKG_CONFIG"; then + if test -n "$SNDFILE_CFLAGS"; then + pkg_cv_SNDFILE_CFLAGS="$SNDFILE_CFLAGS" + else + if test -n "$PKG_CONFIG" && \ + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"sndfile\"") >&5 + ($PKG_CONFIG --exists --print-errors "sndfile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + pkg_cv_SNDFILE_CFLAGS=`$PKG_CONFIG --cflags "sndfile" 2>/dev/null` +else + pkg_failed=yes +fi + fi +else + pkg_failed=untried +fi +if test -n "$PKG_CONFIG"; then + if test -n "$SNDFILE_LIBS"; then + pkg_cv_SNDFILE_LIBS="$SNDFILE_LIBS" + else + if test -n "$PKG_CONFIG" && \ + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"sndfile\"") >&5 + ($PKG_CONFIG --exists --print-errors "sndfile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + pkg_cv_SNDFILE_LIBS=`$PKG_CONFIG --libs "sndfile" 2>/dev/null` +else + pkg_failed=yes +fi + fi +else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + SNDFILE_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "sndfile"` + else + SNDFILE_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "sndfile"` + fi + # Put the nasty error message in config.log where it belongs + echo "$SNDFILE_PKG_ERRORS" >&5 + + { { echo "$as_me:$LINENO: error: Package requirements (sndfile) were not met: + +$SNDFILE_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables SNDFILE_CFLAGS +and SNDFILE_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. +" >&5 +echo "$as_me: error: Package requirements (sndfile) were not met: + +$SNDFILE_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables SNDFILE_CFLAGS +and SNDFILE_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. +" >&2;} + { (exit 1); exit 1; }; } +elif test $pkg_failed = untried; then + { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables SNDFILE_CFLAGS +and SNDFILE_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See \`config.log' for more details." >&5 +echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables SNDFILE_CFLAGS +and SNDFILE_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +else + SNDFILE_CFLAGS=$pkg_cv_SNDFILE_CFLAGS + SNDFILE_LIBS=$pkg_cv_SNDFILE_LIBS + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + : +fi + + + + +pkg_failed=no +{ echo "$as_me:$LINENO: checking for FFTW" >&5 +echo $ECHO_N "checking for FFTW... $ECHO_C" >&6; } + +if test -n "$PKG_CONFIG"; then + if test -n "$FFTW_CFLAGS"; then + pkg_cv_FFTW_CFLAGS="$FFTW_CFLAGS" + else + if test -n "$PKG_CONFIG" && \ + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"fftw3\"") >&5 + ($PKG_CONFIG --exists --print-errors "fftw3") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + pkg_cv_FFTW_CFLAGS=`$PKG_CONFIG --cflags "fftw3" 2>/dev/null` +else + pkg_failed=yes +fi + fi +else + pkg_failed=untried +fi +if test -n "$PKG_CONFIG"; then + if test -n "$FFTW_LIBS"; then + pkg_cv_FFTW_LIBS="$FFTW_LIBS" + else + if test -n "$PKG_CONFIG" && \ + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"fftw3\"") >&5 + ($PKG_CONFIG --exists --print-errors "fftw3") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + pkg_cv_FFTW_LIBS=`$PKG_CONFIG --libs "fftw3" 2>/dev/null` +else + pkg_failed=yes +fi + fi +else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + FFTW_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "fftw3"` + else + FFTW_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "fftw3"` + fi + # Put the nasty error message in config.log where it belongs + echo "$FFTW_PKG_ERRORS" >&5 + + { { echo "$as_me:$LINENO: error: Package requirements (fftw3) were not met: + +$FFTW_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables FFTW_CFLAGS +and FFTW_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. +" >&5 +echo "$as_me: error: Package requirements (fftw3) were not met: + +$FFTW_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables FFTW_CFLAGS +and FFTW_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. +" >&2;} + { (exit 1); exit 1; }; } +elif test $pkg_failed = untried; then + { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables FFTW_CFLAGS +and FFTW_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See \`config.log' for more details." >&5 +echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables FFTW_CFLAGS +and FFTW_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +else + FFTW_CFLAGS=$pkg_cv_FFTW_CFLAGS + FFTW_LIBS=$pkg_cv_FFTW_LIBS + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + : +fi + + + + +for ac_header in ladspa.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ------------------------------------------- ## +## Report this to cannam@all-day-breakfast.com ## +## ------------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in pthread.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ------------------------------------------- ## +## Report this to cannam@all-day-breakfast.com ## +## ------------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +pkg_failed=no +{ echo "$as_me:$LINENO: checking for Vamp" >&5 +echo $ECHO_N "checking for Vamp... $ECHO_C" >&6; } + +if test -n "$PKG_CONFIG"; then + if test -n "$Vamp_CFLAGS"; then + pkg_cv_Vamp_CFLAGS="$Vamp_CFLAGS" + else + if test -n "$PKG_CONFIG" && \ + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"vamp-sdk\"") >&5 + ($PKG_CONFIG --exists --print-errors "vamp-sdk") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + pkg_cv_Vamp_CFLAGS=`$PKG_CONFIG --cflags "vamp-sdk" 2>/dev/null` +else + pkg_failed=yes +fi + fi +else + pkg_failed=untried +fi +if test -n "$PKG_CONFIG"; then + if test -n "$Vamp_LIBS"; then + pkg_cv_Vamp_LIBS="$Vamp_LIBS" + else + if test -n "$PKG_CONFIG" && \ + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"vamp-sdk\"") >&5 + ($PKG_CONFIG --exists --print-errors "vamp-sdk") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + pkg_cv_Vamp_LIBS=`$PKG_CONFIG --libs "vamp-sdk" 2>/dev/null` +else + pkg_failed=yes +fi + fi +else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + Vamp_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "vamp-sdk"` + else + Vamp_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "vamp-sdk"` + fi + # Put the nasty error message in config.log where it belongs + echo "$Vamp_PKG_ERRORS" >&5 + + { { echo "$as_me:$LINENO: error: Package requirements (vamp-sdk) were not met: + +$Vamp_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables Vamp_CFLAGS +and Vamp_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. +" >&5 +echo "$as_me: error: Package requirements (vamp-sdk) were not met: + +$Vamp_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +Alternatively, you may set the environment variables Vamp_CFLAGS +and Vamp_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. +" >&2;} + { (exit 1); exit 1; }; } +elif test $pkg_failed = untried; then + { { echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables Vamp_CFLAGS +and Vamp_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See \`config.log' for more details." >&5 +echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +Alternatively, you may set the environment variables Vamp_CFLAGS +and Vamp_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details. + +To get pkg-config, see <http://pkg-config.freedesktop.org/>. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +else + Vamp_CFLAGS=$pkg_cv_Vamp_CFLAGS + Vamp_LIBS=$pkg_cv_Vamp_LIBS + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + : +fi + + + +if test "x$GCC" = "xyes"; then + case " $CXXFLAGS " in + *[\ \ ]-fPIC\ -Wall[\ \ ]*) ;; + *) CXXFLAGS="$CXXFLAGS -fPIC -Wall" ;; + esac +fi + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by RubberBand $as_me 0.1, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Report bugs to <bug-autoconf@gnu.org>." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +RubberBand config.status 0.1 +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +CXX!$CXX$ac_delim +CXXFLAGS!$CXXFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CXX!$ac_ct_CXX$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +CC!$CC$ac_delim +CFLAGS!$CFLAGS$ac_delim +ac_ct_CC!$ac_ct_CC$ac_delim +CPP!$CPP$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +PKG_CONFIG!$PKG_CONFIG$ac_delim +SRC_CFLAGS!$SRC_CFLAGS$ac_delim +SRC_LIBS!$SRC_LIBS$ac_delim +SNDFILE_CFLAGS!$SNDFILE_CFLAGS$ac_delim +SNDFILE_LIBS!$SNDFILE_LIBS$ac_delim +FFTW_CFLAGS!$FFTW_CFLAGS$ac_delim +FFTW_LIBS!$FFTW_LIBS$ac_delim +Vamp_CFLAGS!$Vamp_CFLAGS$ac_delim +Vamp_LIBS!$Vamp_LIBS$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 61; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS <conf$$subs.sed +rm -f conf$$subs.sed +cat >>$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + + + + esac + +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + + diff --git a/libs/rubberband/1.0/configure.ac b/libs/rubberband/1.0/configure.ac new file mode 100644 index 0000000000..83da151ba3 --- /dev/null +++ b/libs/rubberband/1.0/configure.ac @@ -0,0 +1,38 @@ + +AC_INIT(RubberBand, 0.1, cannam@all-day-breakfast.com) + +AC_CONFIG_SRCDIR(src/StretcherImpl.h) +AC_PROG_CXX +AC_HEADER_STDC +AC_C_BIGENDIAN + +PKG_CHECK_MODULES([SRC],[samplerate]) +AC_SUBST(SRC_CFLAGS) +AC_SUBST(SRC_LIBS) + +PKG_CHECK_MODULES([SNDFILE],[sndfile]) +AC_SUBST(SNDFILE_CFLAGS) +AC_SUBST(SNDFILE_LIBS) + +PKG_CHECK_MODULES([FFTW],[fftw3]) +AC_SUBST(FFTW_CFLAGS) +AC_SUBST(FFTW_LIBS) + +AC_CHECK_HEADERS(ladspa.h) +AC_CHECK_HEADERS(pthread.h) + +PKG_CHECK_MODULES([Vamp],[vamp-sdk]) +AC_SUBST(Vamp_CFLAGS) +AC_SUBST(Vamp_LIBS) + +changequote(,)dnl +if test "x$GCC" = "xyes"; then + case " $CXXFLAGS " in + *[\ \ ]-fPIC\ -Wall[\ \ ]*) ;; + *) CXXFLAGS="$CXXFLAGS -fPIC -Wall" ;; + esac +fi +changequote([,])dnl + +AC_OUTPUT([Makefile]) + diff --git a/libs/rubberband/1.0/misc/Makefile.osx b/libs/rubberband/1.0/misc/Makefile.osx new file mode 100644 index 0000000000..ecef7ab164 --- /dev/null +++ b/libs/rubberband/1.0/misc/Makefile.osx @@ -0,0 +1,144 @@ + +CXX = g++ +CXXFLAGS = -isysroot /Developer/SDKs/MacOSX10.4u.sdk -O3 -arch i386 -arch ppc -msse -msse2 -I../include -I../vamp-plugin-sdk -Irubberband -Isrc +LDFLAGS = -L../lib -L../vamp-plugin-sdk/vamp-sdk + +LIBRARY_LIBS = -lsamplerate -lfftw3 -lfftw3f +PROGRAM_LIBS = -lsndfile $(LIBRARY_LIBS) +VAMP_PLUGIN_LIBS = -lvamp-sdk $(LIBRARY_LIBS) +LADSPA_PLUGIN_LIBS = $(LIBRARY_LIBS) + +MKDIR = mkdir +AR = ar + +PROGRAM_TARGET := bin/rubberband +STATIC_TARGET := lib/librubberband.a +DYNAMIC_TARGET := lib/librubberband.dylib +VAMP_TARGET := lib/vamp-rubberband.dylib +LADSPA_TARGET := lib/ladspa-rubberband.dylib + +#DYNAMIC_LDFLAGS := -shared -Wl,-Bsymbolic +DYNAMIC_LDFLAGS := -dynamiclib + +all: bin lib $(PROGRAM_TARGET) $(STATIC_TARGET) $(DYNAMIC_TARGET) $(VAMP_TARGET) $(LADSPA_TARGET) + +PUBLIC_INCLUDES := \ + rubberband/TimeStretcher.h \ + rubberband/RubberBandStretcher.h + +LIBRARY_INCLUDES := \ + src/AudioCurve.h \ + src/ConstantAudioCurve.h \ + src/FFT.h \ + src/HighFrequencyAudioCurve.h \ + src/PercussiveAudioCurve.h \ + src/Resampler.h \ + src/RingBuffer.h \ + src/Scavenger.h \ + src/StretchCalculator.h \ + src/StretcherImpl.h \ + src/StretcherChannelData.h \ + src/Thread.h \ + src/Window.h \ + src/sysutils.h + +LIBRARY_SOURCES := \ + src/RubberBandStretcher.cpp \ + src/ConstantAudioCurve.cpp \ + src/HighFrequencyAudioCurve.cpp \ + src/PercussiveAudioCurve.cpp \ + src/AudioCurve.cpp \ + src/Resampler.cpp \ + src/StretchCalculator.cpp \ + src/StretcherImpl.cpp \ + src/StretcherProcess.cpp \ + src/StretcherChannelData.cpp \ + src/FFT.cpp \ + src/Thread.cpp \ + src/sysutils.cpp + +PROGRAM_SOURCES := \ + src/main.cpp + +VAMP_HEADERS := \ + src/vamp/RubberBandVampPlugin.h + +VAMP_SOURCES := \ + src/vamp/RubberBandVampPlugin.cpp \ + src/vamp/libmain.cpp + +LADSPA_HEADERS := \ + src/ladspa/RubberBandPitchShifter.h + +LADSPA_SOURCES := \ + src/ladspa/RubberBandPitchShifter.cpp \ + src/ladspa/libmain.cpp + +LIBRARY_OBJECTS := $(LIBRARY_SOURCES:.cpp=.o) +PROGRAM_OBJECTS := $(PROGRAM_SOURCES:.cpp=.o) +VAMP_OBJECTS := $(VAMP_SOURCES:.cpp=.o) +LADSPA_OBJECTS := $(LADSPA_SOURCES:.cpp=.o) + +$(PROGRAM_TARGET): $(LIBRARY_OBJECTS) $(PROGRAM_OBJECTS) + $(CXX) -o $@ $^ $(PROGRAM_LIBS) $(PROGRAM_LIBS) $(LDFLAGS) + +$(STATIC_TARGET): $(LIBRARY_OBJECTS) + $(AR) rsc $@ $^ + +$(DYNAMIC_TARGET): $(LIBRARY_OBJECTS) + $(CXX) $(DYNAMIC_LDFLAGS) $^ -o $@ $(LIBRARY_LIBS) $(LDFLAGS) + +$(VAMP_TARGET): $(LIBRARY_OBJECTS) $(VAMP_OBJECTS) + $(CXX) $(DYNAMIC_LDFLAGS) -o $@ $^ $(VAMP_PLUGIN_LIBS) $(LDFLAGS) + +$(LADSPA_TARGET): $(LIBRARY_OBJECTS) $(LADSPA_OBJECTS) + $(CXX) $(DYNAMIC_LDFLAGS) -o $@ $^ $(LADSPA_PLUGIN_LIBS) $(LDFLAGS) + +bin: + $(MKDIR) $@ +lib: + $(MKDIR) $@ + +clean: + rm -f $(LIBRARY_OBJECTS) $(PROGRAM_OBJECTS) $(LADSPA_OBJECTS) $(VAMP_OBJECTS) + +distclean: clean + rm -f $(PROGRAM_TARGET) $(STATIC_TARGET) $(DYNAMIC_TARGET) $(VAMP_TARGET) $(LADSPA_TARGET) + +# DO NOT DELETE + +src/AudioCurve.o: src/AudioCurve.h +src/ConstantAudioCurve.o: src/ConstantAudioCurve.h src/AudioCurve.h +src/FFT.o: src/FFT.h src/Thread.h +src/HighFrequencyAudioCurve.o: src/HighFrequencyAudioCurve.h src/AudioCurve.h +src/HighFrequencyAudioCurve.o: src/Window.h +src/main.o: rubberband/RubberBandStretcher.h rubberband/TimeStretcher.h +src/PercussiveAudioCurve.o: src/PercussiveAudioCurve.h src/AudioCurve.h +src/Resampler.o: src/Resampler.h +src/RubberBandStretcher.o: src/StretcherImpl.h +src/RubberBandStretcher.o: rubberband/RubberBandStretcher.h +src/RubberBandStretcher.o: rubberband/TimeStretcher.h src/Window.h +src/RubberBandStretcher.o: src/Thread.h src/RingBuffer.h src/Scavenger.h +src/RubberBandStretcher.o: src/FFT.h src/sysutils.h +src/StretchCalculator.o: src/StretchCalculator.h +src/StretcherChannelData.o: src/StretcherChannelData.h src/StretcherImpl.h +src/StretcherChannelData.o: rubberband/RubberBandStretcher.h +src/StretcherChannelData.o: rubberband/TimeStretcher.h src/Window.h +src/StretcherChannelData.o: src/Thread.h src/RingBuffer.h src/Scavenger.h +src/StretcherChannelData.o: src/FFT.h src/sysutils.h src/Resampler.h +src/StretcherImpl.o: src/StretcherImpl.h rubberband/RubberBandStretcher.h +src/StretcherImpl.o: rubberband/TimeStretcher.h src/Window.h src/Thread.h +src/StretcherImpl.o: src/RingBuffer.h src/Scavenger.h src/FFT.h +src/StretcherImpl.o: src/sysutils.h src/PercussiveAudioCurve.h +src/StretcherImpl.o: src/AudioCurve.h src/HighFrequencyAudioCurve.h +src/StretcherImpl.o: src/ConstantAudioCurve.h src/StretchCalculator.h +src/StretcherImpl.o: src/StretcherChannelData.h src/Resampler.h +src/StretcherProcess.o: src/StretcherImpl.h rubberband/RubberBandStretcher.h +src/StretcherProcess.o: rubberband/TimeStretcher.h src/Window.h src/Thread.h +src/StretcherProcess.o: src/RingBuffer.h src/Scavenger.h src/FFT.h +src/StretcherProcess.o: src/sysutils.h src/PercussiveAudioCurve.h +src/StretcherProcess.o: src/AudioCurve.h src/HighFrequencyAudioCurve.h +src/StretcherProcess.o: src/ConstantAudioCurve.h src/StretchCalculator.h +src/StretcherProcess.o: src/StretcherChannelData.h src/Resampler.h +src/sysutils.o: src/sysutils.h +src/Thread.o: src/Thread.h diff --git a/libs/rubberband/1.0/rubberband.pc.in b/libs/rubberband/1.0/rubberband.pc.in new file mode 100644 index 0000000000..580fea38f2 --- /dev/null +++ b/libs/rubberband/1.0/rubberband.pc.in @@ -0,0 +1,10 @@ +prefix=%PREFIX% +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: rubberband +Version: 1.0 +Description: +Libs: -L${libdir} -lrubberband +Cflags: -I${includedir} diff --git a/libs/rubberband/1.0/rubberband/RubberBandStretcher.h b/libs/rubberband/1.0/rubberband/RubberBandStretcher.h new file mode 100644 index 0000000000..94f1e88e2d --- /dev/null +++ b/libs/rubberband/1.0/rubberband/RubberBandStretcher.h @@ -0,0 +1,410 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBANDSTRETCHER_H_ +#define _RUBBERBANDSTRETCHER_H_ + +#include "TimeStretcher.h" + +#include <vector> + +namespace RubberBand +{ + +class RubberBandStretcher : public TimeStretcher +{ +public: + + /** + * Processing options for the timestretcher. The preferred + * options should normally be set in the constructor, as a bitwise + * OR of the option flags. The default value (DefaultOptions) is + * intended to give good results in most situations. + * + * 1. Flags prefixed \c OptionProcess determine how the timestretcher + * will be invoked. These options may not be changed after + * construction. + * + * \li \c OptionProcessOffline - Run the stretcher in offline + * mode. In this mode the input data needs to be provided + * twice, once to study(), which calculates a stretch profile + * for the audio, and once to process(), which stretches it. + * + * \li \c OptionProcessRealTime - Run the stretcher in real-time + * mode. In this mode only process() should be called, and the + * stretcher adjusts dynamically in response to the input audio. + * + * The Process setting is likely to depend on your architecture: + * non-real-time operation on seekable files: Offline; real-time + * or streaming operation: RealTime. + * + * 2. Flags prefixed \c OptionStretch control the profile used for + * variable timestretching. Rubber Band always adjusts the + * stretch profile to minimise stretching of busy broadband + * transient sounds, but the degree to which it does so is + * adjustable. These options may not be changed after + * construction. + * + * \li \c OptionStretchElastic - Only meaningful in offline + * mode, and the default in that mode. The audio will be + * stretched at a variable rate, aimed at preserving the quality + * of transient sounds as much as possible. The timings of low + * activity regions between transients may be less exact than + * when the precise flag is set. + * + * \li \c OptionStretchPrecise - Although still using a variable + * stretch rate, the audio will be stretched so as to maintain + * as close as possible to a linear stretch ratio throughout. + * Timing may be better than when using \c OptionStretchElastic, at + * slight cost to the sound quality of transients. This setting + * is always used when running in real-time mode. + * + * 3. Flags prefixed \c OptionTransients control the component + * frequency phase-reset mechanism that may be used at transient + * points to provide clarity and realism to percussion and other + * significant transient sounds. These options may be changed + * after construction when running in real-time mode, but not when + * running in offline mode. + * + * \li \c OptionTransientsCrisp - Reset component phases at the + * peak of each transient (the start of a significant note or + * percussive event). This, the default setting, usually + * results in a clear-sounding output; but it is not always + * consistent, and may cause interruptions in stable sounds + * present at the same time as transient events. + * + * \li \c OptionTransientsMixed - Reset component phases at the + * peak of each transient, outside a frequency range typical of + * musical fundamental frequencies. The results may be more + * regular for mixed stable and percussive notes than + * \c OptionTransientsCrisp, but with a "phasier" sound. The + * balance may sound very good for certain types of music and + * fairly bad for others. + * + * \li \c OptionTransientsSmooth - Do not reset component phases + * at any point. The results will be smoother and more regular + * but may be less clear than with either of the other + * transients flags. + * + * 4. Flags prefixed \c OptionPhase control the adjustment of + * component frequency phases from one analysis window to the next + * during non-transient segments. These options may be changed at + * any time. + * + * \li \c OptionPhaseAdaptive - Lock the adjustments of phase + * for frequencies close to peak frequencies to those of the + * peak, but reduce the degree of locking as the stretch ratio + * gets longer. This, the default setting, should give a good + * balance between clarity and smoothness in most situations. + * + * \li \c OptionPhasePeakLocked - Lock the adjustments of phase + * for frequencies close to peak frequencies to those of the + * peak. This should give a clear result in situations with + * relatively low stretch ratios, but a relatively metallic + * sound at longer stretches. + * + * \li \c OptionPhaseIndependent - Do not lock phase adjustments + * to peak frequencies. This usually results in a softer, + * phasier sound. + * + * 5. Flags prefixed \c OptionThreading control the threading + * model of the stretcher. These options may not be changed after + * construction. + * + * \li \c OptionThreadingAuto - Permit the stretcher to + * determine its own threading model. Usually this means using + * one processing thread per audio channel in offline mode if + * the stretcher is able to determine that more than one CPU is + * available, and one thread only in realtime mode. + * + * \li \c OptionThreadingNever - Never use more than one thread. + * + * \li \c OptionThreadingAlways - Use multiple threads in any + * situation where \c OptionThreadingAuto would do so, except omit + * the check for multiple CPUs and instead assume it to be true. + * + * 6. Flags prefixed \c OptionWindow control the window size for + * FFT processing. The window size actually used will depend on + * many factors, but it can be influenced. These options may not + * be changed after construction. + * + * \li \c OptionWindowStandard - Use the default window size. + * The actual size will vary depending on other parameters. + * This option is expected to produce better results than the + * other window options in most situations. + * + * \li \c OptionWindowShort - Use a shorter window. This may + * result in crisper sound for audio that depends strongly on + * its timing qualities. + * + * \li \c OptionWindowLong - Use a longer window. This is + * likely to result in a smoother sound at the expense of + * clarity and timing. + */ + typedef int Options; + + static const int OptionProcessOffline = 0x00000000; + static const int OptionProcessRealTime = 0x00000001; + + static const int OptionStretchElastic = 0x00000000; + static const int OptionStretchPrecise = 0x00000010; + + static const int OptionTransientsCrisp = 0x00000000; + static const int OptionTransientsMixed = 0x00000100; + static const int OptionTransientsSmooth = 0x00000200; + + static const int OptionPhaseAdaptive = 0x00000000; + static const int OptionPhasePeakLocked = 0x00001000; + static const int OptionPhaseIndependent = 0x00002000; + + static const int OptionThreadingAuto = 0x00000000; + static const int OptionThreadingNever = 0x00010000; + static const int OptionThreadingAlways = 0x00020000; + + static const int OptionWindowStandard = 0x00000000; + static const int OptionWindowShort = 0x00100000; + static const int OptionWindowLong = 0x00200000; + + static const int DefaultOptions = 0x00000000; + static const int PercussiveOptions = OptionWindowShort | \ + OptionPhaseIndependent; + + /** + * Construct a time and pitch stretcher object to run at the given + * sample rate, with the given number of channels. Processing + * options and the time and pitch scaling ratios may be provided. + * The time and pitch ratios may be changed after construction, + * but most of the options may not. See the option documentation + * above for more details. + */ + RubberBandStretcher(size_t sampleRate, + size_t channels, + Options options = DefaultOptions, + double initialTimeRatio = 1.0, + double initialPitchScale = 1.0); + virtual ~RubberBandStretcher(); + + /** + * Reset the stretcher's internal buffers. The stretcher should + * subsequently behave as if it had just been constructed + * (although retaining the current time and pitch ratio). + */ + virtual void reset(); + + /** + * Set the time ratio for the stretcher. This is the ratio of + * stretched to unstretched duration -- not tempo. For example, a + * ratio of 2.0 would make the audio twice as long (i.e. halve the + * tempo); 0.5 would make it half as long (i.e. double the tempo); + * 1.0 would leave the duration unaffected. + * + * If the stretcher was constructed in Offline mode, the time + * ratio is fixed throughout operation; this function may be + * called any number of times between construction (or a call to + * reset()) and the first call to study() or process(), but may + * not be called after study() or process() has been called. + * + * If the stretcher was constructed in RealTime mode, the time + * ratio may be varied during operation; this function may be + * called at any time, so long as it is not called concurrently + * with process(). You should either call this function from the + * same thread as process(), or provide your own mutex or similar + * mechanism to ensure that setTimeRatio and process() cannot be + * run at once (there is no internal mutex for this purpose). + */ + virtual void setTimeRatio(double ratio); + + /** + * Set the pitch scaling ratio for the stretcher. This is the + * ratio of target frequency to source frequency. For example, a + * ratio of 2.0 would shift up by one octave; 0.5 down by one + * octave; or 1.0 leave the pitch unaffected. + * + * To put this in musical terms, a pitch scaling ratio + * corresponding to a shift of S equal-tempered semitones (where S + * is positive for an upwards shift and negative for downwards) is + * pow(2.0, S / 12.0). + * + * If the stretcher was constructed in Offline mode, the pitch + * scaling ratio is fixed throughout operation; this function may + * be called any number of times between construction (or a call + * to reset()) and the first call to study() or process(), but may + * not be called after study() or process() has been called. + * + * If the stretcher was constructed in RealTime mode, the pitch + * scaling ratio may be varied during operation; this function may + * be called at any time, so long as it is not called concurrently + * with process(). You should either call this function from the + * same thread as process(), or provide your own mutex or similar + * mechanism to ensure that setPitchScale and process() cannot be + * run at once (there is no internal mutex for this purpose). + */ + virtual void setPitchScale(double scale); + + /** + * Return the last time ratio value that was set (either on + * construction or with setTimeRatio()). + */ + virtual double getTimeRatio() const; + + /** + * Return the last pitch scaling ratio value that was set (either + * on construction or with setPitchScale()). + */ + virtual double getPitchScale() const; + + /** + * Return the processing latency of the stretcher. This is the + * number of audio samples that one would have to discard at the + * start of the output in order to ensure that the resulting audio + * aligned with the input audio at the start. In Offline mode, + * latency is automatically adjusted for and the result is zero. + * In RealTime mode, the latency may depend on the time and pitch + * ratio and other options. + */ + virtual size_t getLatency() const; + + /** + * Change an OptionTransients configuration setting. This may be + * called at any time in RealTime mode. It may not be called in + * Offline mode (for which the transients option is fixed on + * construction). + */ + virtual void setTransientsOption(Options options); + + /** + * Change an OptionPhase configuration setting. This may be + * called at any time in any mode. + * + * Note that if running multi-threaded in Offline mode, the change + * may not take effect immediately if processing is already under + * way when this function is called. + */ + virtual void setPhaseOption(Options options); + + /** + * Tell the stretcher exactly how many input samples it will + * receive. This is only useful in Offline mode, when it allows + * the stretcher to ensure that the number of output samples is + * exactly correct. In RealTime mode no such guarantee is + * possible and this value is ignored. + */ + virtual void setExpectedInputDuration(size_t samples); + + /** + * Ask the stretcher how many audio sample frames should be + * provided as input in order to ensure that some more output + * becomes available. Normal usage consists of querying this + * function, providing that number of samples to process(), + * reading the output using available() and retrieve(), and then + * repeating. + * + * Note that this value is only relevant to process(), not to + * study() (to which you may pass any number of samples at a time, + * and from which there is no output). + */ + virtual size_t getSamplesRequired() const; + + /** + * Tell the stretcher the maximum number of sample frames that you + * will ever be passing in to a single process() call. If you + * don't call this function, the stretcher will assume that you + * never pass in more samples than getSamplesRequired() suggested + * you should. You should not pass in more samples than that + * unless you have called setMaxProcessSize first. + * + * This function may not be called after the first call to study() + * or process(). + * + * Note that this value is only relevant to process(), not to + * study() (to which you may pass any number of samples at a time, + * and from which there is no output). + */ + virtual void setMaxProcessSize(size_t samples); + + /** + * Provide a block of "samples" sample frames for the stretcher to + * study and calculate a stretch profile from. + * + * This is only meaningful in Offline mode, and is required if + * running in that mode. You should pass the entire input through + * study() before any process() calls are made, as a sequence of + * blocks in individual study() calls, or as a single large block. + * + * "input" should point to de-interleaved audio data with one + * float array per channel. "samples" supplies the number of + * audio sample frames available in "input". If "samples" is + * zero, "input" may be NULL. + * + * Set "final" to true if this is the last block of data that will + * be provided to study() before the first process() call. + */ + virtual void study(const float *const *input, size_t samples, bool final); + + /** + * Provide a block of "samples" sample frames for processing. + * See also getSamplesRequired() and setMaxProcessSize(). + * + * Set "final" to true if this is the last block of input data. + */ + virtual void process(const float *const *input, size_t samples, bool final); + + /** + * Ask the stretcher how many audio sample frames of output data + * are available for reading (via retrieve()). + * + * This function returns 0 if no frames are available: this + * usually means more input data needs to be provided, but if the + * stretcher is running in threaded mode it may just mean that not + * enough data has yet been processed. Call getSamplesRequired() + * to discover whether more input is needed. + * + * This function returns -1 if all data has been fully processed + * and all output read, and the stretch process is now finished. + */ + virtual int available() const; + + /** + * Obtain some processed output data from the stretcher. Up to + * "samples" samples will be stored in the output arrays (one per + * channel for de-interleaved audio data) pointed to by "output". + * The return value is the actual number of sample frames + * retrieved. + */ + virtual size_t retrieve(float *const *output, size_t samples) const; + + virtual float getFrequencyCutoff(int n) const; + virtual void setFrequencyCutoff(int n, float f); + + virtual size_t getInputIncrement() const; + virtual std::vector<int> getOutputIncrements() const; //!!! document particular meaning in RT mode + virtual std::vector<float> getPhaseResetCurve() const; //!!! document particular meaning in RT mode + virtual std::vector<int> getExactTimePoints() const; //!!! meaningless in RT mode + + virtual size_t getChannelCount() const; + + virtual void calculateStretch(); + + virtual void setDebugLevel(int level); + + static void setDefaultDebugLevel(int level); + +protected: + class Impl; + Impl *m_d; +}; + +} + +#endif diff --git a/libs/rubberband/1.0/rubberband/TimeStretcher.h b/libs/rubberband/1.0/rubberband/TimeStretcher.h new file mode 100644 index 0000000000..bad916a75c --- /dev/null +++ b/libs/rubberband/1.0/rubberband/TimeStretcher.h @@ -0,0 +1,58 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_TIMESTRETCHER_H_ +#define _RUBBERBAND_TIMESTRETCHER_H_ + +#include <sys/types.h> + +namespace RubberBand +{ + +/** + * Base class for time stretchers. RubberBand currently provides only + * a single subclass implementation. + * + * @see RubberBandStretcher + */ +class TimeStretcher +{ +public: + TimeStretcher(size_t sampleRate, size_t channels) : + m_sampleRate(sampleRate), + m_channels(channels) + { } + virtual ~TimeStretcher() + { } + + virtual void reset() = 0; + virtual void setTimeRatio(double ratio) = 0; + virtual void setPitchScale(double scale) = 0; + virtual size_t getLatency() const = 0; + + virtual void study(const float *const *input, size_t samples, bool final) = 0; + virtual size_t getSamplesRequired() const = 0; + virtual void process(const float *const *input, size_t samples, bool final) = 0; + virtual int available() const = 0; + virtual size_t retrieve(float *const *output, size_t samples) const = 0; + +protected: + size_t m_sampleRate; + size_t m_channels; +}; + +} + +#endif + diff --git a/libs/rubberband/1.0/src/AudioCurve.cpp b/libs/rubberband/1.0/src/AudioCurve.cpp new file mode 100644 index 0000000000..c18d134b0d --- /dev/null +++ b/libs/rubberband/1.0/src/AudioCurve.cpp @@ -0,0 +1,31 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "AudioCurve.h" + +namespace RubberBand +{ + +AudioCurve::AudioCurve(size_t sampleRate, size_t windowSize) : + m_sampleRate(sampleRate), + m_windowSize(windowSize) +{ +} + +AudioCurve::~AudioCurve() +{ +} + + +} diff --git a/libs/rubberband/1.0/src/AudioCurve.h b/libs/rubberband/1.0/src/AudioCurve.h new file mode 100644 index 0000000000..e7a57c52a2 --- /dev/null +++ b/libs/rubberband/1.0/src/AudioCurve.h @@ -0,0 +1,42 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _AUDIO_CURVE_H_ +#define _AUDIO_CURVE_H_ + +#include <sys/types.h> + +namespace RubberBand +{ + +class AudioCurve +{ +public: + AudioCurve(size_t sampleRate, size_t windowSize); + virtual ~AudioCurve(); + + virtual void setWindowSize(size_t newSize) = 0; + + virtual float process(float *mag, size_t increment) = 0; + virtual void reset() = 0; + +protected: + size_t m_sampleRate; + size_t m_windowSize; +}; + +} + +#endif + diff --git a/libs/rubberband/1.0/src/ConstantAudioCurve.cpp b/libs/rubberband/1.0/src/ConstantAudioCurve.cpp new file mode 100644 index 0000000000..85c2c67072 --- /dev/null +++ b/libs/rubberband/1.0/src/ConstantAudioCurve.cpp @@ -0,0 +1,47 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "ConstantAudioCurve.h" + +namespace RubberBand +{ + +ConstantAudioCurve::ConstantAudioCurve(size_t sampleRate, size_t windowSize) : + AudioCurve(sampleRate, windowSize) +{ +} + +ConstantAudioCurve::~ConstantAudioCurve() +{ +} + +void +ConstantAudioCurve::reset() +{ +} + +void +ConstantAudioCurve::setWindowSize(size_t newSize) +{ + m_windowSize = newSize; +} + +float +ConstantAudioCurve::process(float *, size_t) +{ + return 1.f; +} + +} + diff --git a/libs/rubberband/1.0/src/ConstantAudioCurve.h b/libs/rubberband/1.0/src/ConstantAudioCurve.h new file mode 100644 index 0000000000..87a4f7526c --- /dev/null +++ b/libs/rubberband/1.0/src/ConstantAudioCurve.h @@ -0,0 +1,37 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _CONSTANT_AUDIO_CURVE_H_ +#define _CONSTANT_AUDIO_CURVE_H_ + +#include "AudioCurve.h" + +namespace RubberBand +{ + +class ConstantAudioCurve : public AudioCurve +{ +public: + ConstantAudioCurve(size_t sampleRate, size_t windowSize); + virtual ~ConstantAudioCurve(); + + virtual void setWindowSize(size_t newSize); + + virtual float process(float *mag, size_t increment); + virtual void reset(); +}; + +} + +#endif diff --git a/libs/rubberband/1.0/src/FFT.cpp b/libs/rubberband/1.0/src/FFT.cpp new file mode 100644 index 0000000000..8347e09805 --- /dev/null +++ b/libs/rubberband/1.0/src/FFT.cpp @@ -0,0 +1,867 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "FFT.h" +#include "Thread.h" + + +#include <fftw3.h> + +#include <cmath> +#include <iostream> +#include <map> +#include <cstdio> +#include <vector> + +namespace RubberBand { + +class FFTImpl +{ +public: + virtual ~FFTImpl() { } + + virtual void initFloat() = 0; + virtual void initDouble() = 0; + + virtual void forward(double *realIn, double *realOut, double *imagOut) = 0; + virtual void forwardPolar(double *realIn, double *magOut, double *phaseOut) = 0; + virtual void forwardMagnitude(double *realIn, double *magOut) = 0; + + virtual void forward(float *realIn, float *realOut, float *imagOut) = 0; + virtual void forwardPolar(float *realIn, float *magOut, float *phaseOut) = 0; + virtual void forwardMagnitude(float *realIn, float *magOut) = 0; + + virtual void inverse(double *realIn, double *imagIn, double *realOut) = 0; + virtual void inversePolar(double *magIn, double *phaseIn, double *realOut) = 0; + + virtual void inverse(float *realIn, float *imagIn, float *realOut) = 0; + virtual void inversePolar(float *magIn, float *phaseIn, float *realOut) = 0; + + virtual float *getFloatTimeBuffer() = 0; + virtual double *getDoubleTimeBuffer() = 0; +}; + + + + +// Define FFTW_DOUBLE_ONLY to make all uses of FFTW functions be +// double-precision (so "float" FFTs are calculated by casting to +// doubles and using the double-precision FFTW function). +// +// Define FFTW_FLOAT_ONLY to make all uses of FFTW functions be +// single-precision (so "double" FFTs are calculated by casting to +// floats and using the single-precision FFTW function). +// +// Neither of these flags is terribly desirable -- FFTW_FLOAT_ONLY +// obviously loses you precision, and neither is handled in the most +// efficient way so any performance improvement will be small at best. +// The only real reason to define either flag would be to avoid +// linking against both fftw3 and fftw3f libraries. + +//#define FFTW_DOUBLE_ONLY 1 +//#define FFTW_FLOAT_ONLY 1 + +#ifdef FFTW_DOUBLE_ONLY +#ifdef FFTW_FLOAT_ONLY +// Can't meaningfully define both +#undef FFTW_DOUBLE_ONLY +#undef FFTW_FLOAT_ONLY +#else /* !FFTW_FLOAT_ONLY */ +#define fftwf_complex fftw_complex +#define fftwf_plan fftw_plan +#define fftwf_plan_dft_r2c_1d fftw_plan_dft_r2c_1d +#define fftwf_plan_dft_c2r_1d fftw_plan_dft_c2r_1d +#define fftwf_destroy_plan fftw_destroy_plan +#define fftwf_malloc fftw_malloc +#define fftwf_free fftw_free +#define fftwf_execute fftw_execute +#define atan2f atan2 +#define sqrtf sqrt +#define cosf cos +#define sinf sin +#endif /* !FFTW_FLOAT_ONLY */ + +#ifdef FFTW_FLOAT_ONLY +#define fftw_complex fftwf_complex +#define fftw_plan fftwf_plan +#define fftw_plan_dft_r2c_1d fftwf_plan_dft_r2c_1d +#define fftw_plan_dft_c2r_1d fftwf_plan_dft_c2r_1d +#define fftw_destroy_plan fftwf_destroy_plan +#define fftw_malloc fftwf_malloc +#define fftw_free fftwf_free +#define fftw_execute fftwf_execute +#define atan2 atan2f +#define sqrt sqrtf +#define cos cosf +#define sif sinf +#endif /* FFTW_FLOAT_ONLY */ + +class D_FFTW : public FFTImpl +{ +public: + D_FFTW(unsigned int size) : m_fplanf(0) +#ifdef FFTW_DOUBLE_ONLY + , m_frb(0) +#endif + , m_dplanf(0) +#ifdef FFTW_FLOAT_ONLY + , m_drb(0) +#endif + , m_size(size) + { + } + + ~D_FFTW() { + if (m_fplanf) { + bool save = false; + m_extantMutex.lock(); + if (m_extantf > 0 && --m_extantf == 0) save = true; + m_extantMutex.unlock(); + if (save) saveWisdom('f'); + fftwf_destroy_plan(m_fplanf); + fftwf_destroy_plan(m_fplani); + fftwf_free(m_fbuf); + fftwf_free(m_fpacked); +#ifdef FFTW_DOUBLE_ONLY + if (m_frb) fftw_free(m_frb); +#endif + } + if (m_dplanf) { + bool save = false; + m_extantMutex.lock(); + if (m_extantd > 0 && --m_extantd == 0) save = true; + m_extantMutex.unlock(); + if (save) saveWisdom('d'); + fftw_destroy_plan(m_dplanf); + fftw_destroy_plan(m_dplani); + fftw_free(m_dbuf); + fftw_free(m_dpacked); +#ifdef FFTW_FLOAT_ONLY + if (m_drb) fftwf_free(m_drb); +#endif + } + } + + void initFloat() { + if (m_fplanf) return; + bool load = false; + m_extantMutex.lock(); + if (m_extantf++ == 0) load = true; + m_extantMutex.unlock(); +#ifdef FFTW_DOUBLE_ONLY + if (load) loadWisdom('d'); + m_fbuf = (double *)fftw_malloc(m_size * sizeof(double)); +#else + if (load) loadWisdom('f'); + m_fbuf = (float *)fftwf_malloc(m_size * sizeof(float)); +#endif + m_fpacked = (fftwf_complex *)fftw_malloc + ((m_size/2 + 1) * sizeof(fftwf_complex)); + m_fplanf = fftwf_plan_dft_r2c_1d + (m_size, m_fbuf, m_fpacked, FFTW_MEASURE); + m_fplani = fftwf_plan_dft_c2r_1d + (m_size, m_fpacked, m_fbuf, FFTW_MEASURE); + } + + void initDouble() { + if (m_dplanf) return; + bool load = false; + m_extantMutex.lock(); + if (m_extantd++ == 0) load = true; + m_extantMutex.unlock(); +#ifdef FFTW_FLOAT_ONLY + if (load) loadWisdom('f'); + m_dbuf = (float *)fftwf_malloc(m_size * sizeof(float)); +#else + if (load) loadWisdom('d'); + m_dbuf = (double *)fftw_malloc(m_size * sizeof(double)); +#endif + m_dpacked = (fftw_complex *)fftw_malloc + ((m_size/2 + 1) * sizeof(fftw_complex)); + m_dplanf = fftw_plan_dft_r2c_1d + (m_size, m_dbuf, m_dpacked, FFTW_MEASURE); + m_dplani = fftw_plan_dft_c2r_1d + (m_size, m_dpacked, m_dbuf, FFTW_MEASURE); + } + + void loadWisdom(char type) { wisdom(false, type); } + void saveWisdom(char type) { wisdom(true, type); } + + void wisdom(bool save, char type) { + +#ifdef FFTW_DOUBLE_ONLY + if (type == 'f') return; +#endif +#ifdef FFTW_FLOAT_ONLY + if (type == 'd') return; +#endif + + const char *home = getenv("HOME"); + if (!home) return; + + char fn[256]; + snprintf(fn, 256, "%s/%s.%c", home, ".rubberband.wisdom", type); + + FILE *f = fopen(fn, save ? "wb" : "rb"); + if (!f) return; + + if (save) { + switch (type) { +#ifdef FFTW_DOUBLE_ONLY + case 'f': break; +#else + case 'f': fftwf_export_wisdom_to_file(f); break; +#endif +#ifdef FFTW_FLOAT_ONLY + case 'd': break; +#else + case 'd': fftw_export_wisdom_to_file(f); break; +#endif + default: break; + } + } else { + switch (type) { +#ifdef FFTW_DOUBLE_ONLY + case 'f': break; +#else + case 'f': fftwf_import_wisdom_from_file(f); break; +#endif +#ifdef FFTW_FLOAT_ONLY + case 'd': break; +#else + case 'd': fftw_import_wisdom_from_file(f); break; +#endif + default: break; + } + } + + fclose(f); + } + + void packFloat(float *re, float *im) { + for (unsigned int i = 0; i <= m_size/2; ++i) { + m_fpacked[i][0] = re[i]; + m_fpacked[i][1] = im[i]; + } + } + + void packDouble(double *re, double *im) { + for (unsigned int i = 0; i <= m_size/2; ++i) { + m_dpacked[i][0] = re[i]; + m_dpacked[i][1] = im[i]; + } + } + + void unpackFloat(float *re, float *im) { + for (unsigned int i = 0; i <= m_size/2; ++i) { + re[i] = m_fpacked[i][0]; + im[i] = m_fpacked[i][1]; + } + } + + void unpackDouble(double *re, double *im) { + for (unsigned int i = 0; i <= m_size/2; ++i) { + re[i] = m_dpacked[i][0]; + im[i] = m_dpacked[i][1]; + } + } + + void forward(double *realIn, double *realOut, double *imagOut) { + if (!m_dplanf) initDouble(); +#ifndef FFTW_FLOAT_ONLY + if (realIn != m_dbuf) +#endif + for (unsigned int i = 0; i < m_size; ++i) { + m_dbuf[i] = realIn[i]; + } + fftw_execute(m_dplanf); + unpackDouble(realOut, imagOut); + } + + void forwardPolar(double *realIn, double *magOut, double *phaseOut) { + if (!m_dplanf) initDouble(); +#ifndef FFTW_FLOAT_ONLY + if (realIn != m_dbuf) +#endif + for (unsigned int i = 0; i < m_size; ++i) { + m_dbuf[i] = realIn[i]; + } + fftw_execute(m_dplanf); + for (unsigned int i = 0; i <= m_size/2; ++i) { + magOut[i] = sqrt(m_dpacked[i][0] * m_dpacked[i][0] + + m_dpacked[i][1] * m_dpacked[i][1]); + } + for (unsigned int i = 0; i <= m_size/2; ++i) { + phaseOut[i] = atan2(m_dpacked[i][1], m_dpacked[i][0]); + } + } + + void forwardMagnitude(double *realIn, double *magOut) { + if (!m_dplanf) initDouble(); +#ifndef FFTW_FLOAT_ONLY + if (realIn != m_dbuf) +#endif + for (unsigned int i = 0; i < m_size; ++i) { + m_dbuf[i] = realIn[i]; + } + fftw_execute(m_dplanf); + for (unsigned int i = 0; i <= m_size/2; ++i) { + magOut[i] = sqrt(m_dpacked[i][0] * m_dpacked[i][0] + + m_dpacked[i][1] * m_dpacked[i][1]); + } + } + + void forward(float *realIn, float *realOut, float *imagOut) { + if (!m_fplanf) initFloat(); +#ifndef FFTW_DOUBLE_ONLY + if (realIn != m_fbuf) +#endif + for (unsigned int i = 0; i < m_size; ++i) { + m_fbuf[i] = realIn[i]; + } + fftwf_execute(m_fplanf); + unpackFloat(realOut, imagOut); + } + + void forwardPolar(float *realIn, float *magOut, float *phaseOut) { + if (!m_fplanf) initFloat(); +#ifndef FFTW_DOUBLE_ONLY + if (realIn != m_fbuf) +#endif + for (unsigned int i = 0; i < m_size; ++i) { + m_fbuf[i] = realIn[i]; + } + fftwf_execute(m_fplanf); + for (unsigned int i = 0; i <= m_size/2; ++i) { + magOut[i] = sqrtf(m_fpacked[i][0] * m_fpacked[i][0] + + m_fpacked[i][1] * m_fpacked[i][1]); + } + for (unsigned int i = 0; i <= m_size/2; ++i) { + phaseOut[i] = atan2f(m_fpacked[i][1], m_fpacked[i][0]) ; + } + } + + void forwardMagnitude(float *realIn, float *magOut) { + if (!m_fplanf) initFloat(); +#ifndef FFTW_DOUBLE_ONLY + if (realIn != m_fbuf) +#endif + for (unsigned int i = 0; i < m_size; ++i) { + m_fbuf[i] = realIn[i]; + } + fftwf_execute(m_fplanf); + for (unsigned int i = 0; i <= m_size/2; ++i) { + magOut[i] = sqrtf(m_fpacked[i][0] * m_fpacked[i][0] + + m_fpacked[i][1] * m_fpacked[i][1]); + } + } + + void inverse(double *realIn, double *imagIn, double *realOut) { + if (!m_dplanf) initDouble(); + packDouble(realIn, imagIn); + fftw_execute(m_dplani); +#ifndef FFTW_FLOAT_ONLY + if (realOut != m_dbuf) +#endif + for (unsigned int i = 0; i < m_size; ++i) { + realOut[i] = m_dbuf[i]; + } + } + + void inversePolar(double *magIn, double *phaseIn, double *realOut) { + if (!m_dplanf) initDouble(); + for (unsigned int i = 0; i <= m_size/2; ++i) { + m_dpacked[i][0] = magIn[i] * cos(phaseIn[i]); + m_dpacked[i][1] = magIn[i] * sin(phaseIn[i]); + } + fftw_execute(m_dplani); +#ifndef FFTW_FLOAT_ONLY + if (realOut != m_dbuf) +#endif + for (unsigned int i = 0; i < m_size; ++i) { + realOut[i] = m_dbuf[i]; + } + } + + void inverse(float *realIn, float *imagIn, float *realOut) { + if (!m_fplanf) initFloat(); + packFloat(realIn, imagIn); + fftwf_execute(m_fplani); +#ifndef FFTW_DOUBLE_ONLY + if (realOut != m_fbuf) +#endif + for (unsigned int i = 0; i < m_size; ++i) { + realOut[i] = m_fbuf[i]; + } + } + + void inversePolar(float *magIn, float *phaseIn, float *realOut) { + if (!m_fplanf) initFloat(); + for (unsigned int i = 0; i <= m_size/2; ++i) { + m_fpacked[i][0] = magIn[i] * cosf(phaseIn[i]); + m_fpacked[i][1] = magIn[i] * sinf(phaseIn[i]); + } + fftwf_execute(m_fplani); +#ifndef FFTW_DOUBLE_ONLY + if (realOut != m_fbuf) +#endif + for (unsigned int i = 0; i < m_size; ++i) { + realOut[i] = m_fbuf[i]; + } + } + + float *getFloatTimeBuffer() { + initFloat(); +#ifdef FFTW_DOUBLE_ONLY + if (!m_frb) m_frb = (float *)fftw_malloc(m_size * sizeof(float)); + return m_frb; +#else + return m_fbuf; +#endif + } + + double *getDoubleTimeBuffer() { + initDouble(); +#ifdef FFTW_FLOAT_ONLY + if (!m_drb) m_drb = (double *)fftwf_malloc(m_size * sizeof(double)); + return m_drb; +#else + return m_dbuf; +#endif + } + +private: + fftwf_plan m_fplanf; + fftwf_plan m_fplani; +#ifdef FFTW_DOUBLE_ONLY + float *m_frb; + double *m_fbuf; +#else + float *m_fbuf; +#endif + fftwf_complex *m_fpacked; + fftw_plan m_dplanf; + fftw_plan m_dplani; +#ifdef FFTW_FLOAT_ONLY + float *m_dbuf; + double *m_drb; +#else + double *m_dbuf; +#endif + fftw_complex *m_dpacked; + unsigned int m_size; + static unsigned int m_extantf; + static unsigned int m_extantd; + static Mutex m_extantMutex; +}; + +unsigned int +D_FFTW::m_extantf = 0; + +unsigned int +D_FFTW::m_extantd = 0; + +Mutex +D_FFTW::m_extantMutex; + +#endif + +class D_Cross : public FFTImpl +{ +public: + D_Cross(unsigned int size) : m_size(size), m_table(0), m_frb(0), m_drb(0) { + + m_a = new double[size]; + m_b = new double[size]; + m_c = new double[size]; + m_d = new double[size]; + + m_table = new int[m_size]; + + unsigned int bits; + unsigned int i, j, k, m; + + for (i = 0; ; ++i) { + if (m_size & (1 << i)) { + bits = i; + break; + } + } + + for (i = 0; i < m_size; ++i) { + + m = i; + + for (j = k = 0; j < bits; ++j) { + k = (k << 1) | (m & 1); + m >>= 1; + } + + m_table[i] = k; + } + } + + ~D_Cross() { + delete[] m_table; + delete[] m_a; + delete[] m_b; + delete[] m_c; + delete[] m_d; + delete[] m_frb; + delete[] m_drb; + } + + void initFloat() { } + void initDouble() { } + + void forward(double *realIn, double *realOut, double *imagOut) { + basefft(false, realIn, 0, m_c, m_d); + for (size_t i = 0; i <= m_size/2; ++i) realOut[i] = m_c[i]; + for (size_t i = 0; i <= m_size/2; ++i) imagOut[i] = m_d[i]; + } + + void forwardPolar(double *realIn, double *magOut, double *phaseOut) { + basefft(false, realIn, 0, m_c, m_d); + for (unsigned int i = 0; i <= m_size/2; ++i) { + magOut[i] = sqrt(m_c[i] * m_c[i] + m_d[i] * m_d[i]); + phaseOut[i] = atan2(m_d[i], m_c[i]) ; + } + } + + void forwardMagnitude(double *realIn, double *magOut) { + basefft(false, realIn, 0, m_c, m_d); + for (unsigned int i = 0; i <= m_size/2; ++i) { + magOut[i] = sqrt(m_c[i] * m_c[i] + m_d[i] * m_d[i]); + } + } + + void forward(float *realIn, float *realOut, float *imagOut) { + for (size_t i = 0; i < m_size; ++i) m_a[i] = realIn[i]; + basefft(false, m_a, 0, m_c, m_d); + for (size_t i = 0; i <= m_size/2; ++i) realOut[i] = m_c[i]; + for (size_t i = 0; i <= m_size/2; ++i) imagOut[i] = m_d[i]; + } + + void forwardPolar(float *realIn, float *magOut, float *phaseOut) { + for (size_t i = 0; i < m_size; ++i) m_a[i] = realIn[i]; + basefft(false, m_a, 0, m_c, m_d); + for (unsigned int i = 0; i <= m_size/2; ++i) { + magOut[i] = sqrt(m_c[i] * m_c[i] + m_d[i] * m_d[i]); + phaseOut[i] = atan2(m_d[i], m_c[i]) ; + } + } + + void forwardMagnitude(float *realIn, float *magOut) { + for (size_t i = 0; i < m_size; ++i) m_a[i] = realIn[i]; + basefft(false, m_a, 0, m_c, m_d); + for (unsigned int i = 0; i <= m_size/2; ++i) { + magOut[i] = sqrt(m_c[i] * m_c[i] + m_d[i] * m_d[i]); + } + } + + void inverse(double *realIn, double *imagIn, double *realOut) { + for (unsigned int i = 0; i <= m_size/2; ++i) { + double real = realIn[i]; + double imag = imagIn[i]; + m_a[i] = real; + m_b[i] = imag; + if (i > 0) { + m_a[m_size-i] = real; + m_b[m_size-i] = -imag; + } + } + basefft(true, m_a, m_b, realOut, m_d); + } + + void inversePolar(double *magIn, double *phaseIn, double *realOut) { + for (unsigned int i = 0; i <= m_size/2; ++i) { + double real = magIn[i] * cos(phaseIn[i]); + double imag = magIn[i] * sin(phaseIn[i]); + m_a[i] = real; + m_b[i] = imag; + if (i > 0) { + m_a[m_size-i] = real; + m_b[m_size-i] = -imag; + } + } + basefft(true, m_a, m_b, realOut, m_d); + } + + void inverse(float *realIn, float *imagIn, float *realOut) { + for (unsigned int i = 0; i <= m_size/2; ++i) { + float real = realIn[i]; + float imag = imagIn[i]; + m_a[i] = real; + m_b[i] = imag; + if (i > 0) { + m_a[m_size-i] = real; + m_b[m_size-i] = -imag; + } + } + basefft(true, m_a, m_b, m_c, m_d); + for (unsigned int i = 0; i < m_size; ++i) realOut[i] = m_c[i]; + } + + void inversePolar(float *magIn, float *phaseIn, float *realOut) { + for (unsigned int i = 0; i <= m_size/2; ++i) { + float real = magIn[i] * cosf(phaseIn[i]); + float imag = magIn[i] * sinf(phaseIn[i]); + m_a[i] = real; + m_b[i] = imag; + if (i > 0) { + m_a[m_size-i] = real; + m_b[m_size-i] = -imag; + } + } + basefft(true, m_a, m_b, m_c, m_d); + for (unsigned int i = 0; i < m_size; ++i) realOut[i] = m_c[i]; + } + + float *getFloatTimeBuffer() { + if (!m_frb) m_frb = new float[m_size]; + return m_frb; + } + + double *getDoubleTimeBuffer() { + if (!m_drb) m_drb = new double[m_size]; + return m_drb; + } + +private: + unsigned int m_size; + int *m_table; + float *m_frb; + double *m_drb; + double *m_a; + double *m_b; + double *m_c; + double *m_d; + void basefft(bool inverse, double *ri, double *ii, double *ro, double *io); +}; + +void +D_Cross::basefft(bool inverse, double *ri, double *ii, double *ro, double *io) +{ + if (!ri || !ro || !io) return; + + unsigned int i, j, k, m; + unsigned int blockSize, blockEnd; + + double tr, ti; + + double angle = 2.0 * M_PI; + if (inverse) angle = -angle; + + const unsigned int n = m_size; + + if (ii) { + for (i = 0; i < n; ++i) { + ro[m_table[i]] = ri[i]; + io[m_table[i]] = ii[i]; + } + } else { + for (i = 0; i < n; ++i) { + ro[m_table[i]] = ri[i]; + io[m_table[i]] = 0.0; + } + } + + blockEnd = 1; + + for (blockSize = 2; blockSize <= n; blockSize <<= 1) { + + double delta = angle / (double)blockSize; + double sm2 = -sin(-2 * delta); + double sm1 = -sin(-delta); + double cm2 = cos(-2 * delta); + double cm1 = cos(-delta); + double w = 2 * cm1; + double ar[3], ai[3]; + + for (i = 0; i < n; i += blockSize) { + + ar[2] = cm2; + ar[1] = cm1; + + ai[2] = sm2; + ai[1] = sm1; + + for (j = i, m = 0; m < blockEnd; j++, m++) { + + ar[0] = w * ar[1] - ar[2]; + ar[2] = ar[1]; + ar[1] = ar[0]; + + ai[0] = w * ai[1] - ai[2]; + ai[2] = ai[1]; + ai[1] = ai[0]; + + k = j + blockEnd; + tr = ar[0] * ro[k] - ai[0] * io[k]; + ti = ar[0] * io[k] + ai[0] * ro[k]; + + ro[k] = ro[j] - tr; + io[k] = io[j] - ti; + + ro[j] += tr; + io[j] += ti; + } + } + + blockEnd = blockSize; + } + +/* fftw doesn't rescale, so nor will we + + if (inverse) { + + double denom = (double)n; + + for (i = 0; i < n; i++) { + ro[i] /= denom; + io[i] /= denom; + } + } +*/ +} + +int +FFT::m_method = -1; + +FFT::FFT(unsigned int size) +{ + if (size < 2) throw InvalidSize; + if (size & (size-1)) throw InvalidSize; + + if (m_method == -1) { + m_method = 1; + } + + switch (m_method) { + + case 0: + d = new D_Cross(size); + break; + + case 1: +// std::cerr << "FFT::FFT(" << size << "): using FFTW3 implementation" +// << std::endl; + d = new D_FFTW(size); + break; + + default: + std::cerr << "FFT::FFT(" << size << "): WARNING: using slow built-in implementation" + << std::endl; + d = new D_Cross(size); + break; + } +} + +FFT::~FFT() +{ + delete d; +} + +void +FFT::forward(double *realIn, double *realOut, double *imagOut) +{ + d->forward(realIn, realOut, imagOut); +} + +void +FFT::forwardPolar(double *realIn, double *magOut, double *phaseOut) +{ + d->forwardPolar(realIn, magOut, phaseOut); +} + +void +FFT::forwardMagnitude(double *realIn, double *magOut) +{ + d->forwardMagnitude(realIn, magOut); +} + +void +FFT::forward(float *realIn, float *realOut, float *imagOut) +{ + d->forward(realIn, realOut, imagOut); +} + +void +FFT::forwardPolar(float *realIn, float *magOut, float *phaseOut) +{ + d->forwardPolar(realIn, magOut, phaseOut); +} + +void +FFT::forwardMagnitude(float *realIn, float *magOut) +{ + d->forwardMagnitude(realIn, magOut); +} + +void +FFT::inverse(double *realIn, double *imagIn, double *realOut) +{ + d->inverse(realIn, imagIn, realOut); +} + +void +FFT::inversePolar(double *magIn, double *phaseIn, double *realOut) +{ + d->inversePolar(magIn, phaseIn, realOut); +} + +void +FFT::inverse(float *realIn, float *imagIn, float *realOut) +{ + d->inverse(realIn, imagIn, realOut); +} + +void +FFT::inversePolar(float *magIn, float *phaseIn, float *realOut) +{ + d->inversePolar(magIn, phaseIn, realOut); +} + +void +FFT::initFloat() +{ + d->initFloat(); +} + +void +FFT::initDouble() +{ + d->initDouble(); +} + +float * +FFT::getFloatTimeBuffer() +{ + return d->getFloatTimeBuffer(); +} + +double * +FFT::getDoubleTimeBuffer() +{ + return d->getDoubleTimeBuffer(); +} + + +void +FFT::tune() +{ +} + + +} diff --git a/libs/rubberband/1.0/src/FFT.h b/libs/rubberband/1.0/src/FFT.h new file mode 100644 index 0000000000..65c185de98 --- /dev/null +++ b/libs/rubberband/1.0/src/FFT.h @@ -0,0 +1,76 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_FFT_H_ +#define _RUBBERBAND_FFT_H_ + +namespace RubberBand { + +class FFTImpl; + +/** + * Provide the basic FFT computations we need, using one of a set of + * candidate FFT implementations (depending on compile flags). + * + * Implements real->complex FFTs of power-of-two sizes only. Note + * that only the first half of the output signal is returned (the + * complex conjugates half is omitted), so the "complex" arrays need + * room for size/2+1 elements. + * + * Not thread safe: use a separate instance per thread. + */ + +class FFT +{ +public: + enum Exception { InvalidSize }; + + FFT(unsigned int size); // may throw InvalidSize + ~FFT(); + + void forward(double *realIn, double *realOut, double *imagOut); + void forwardPolar(double *realIn, double *magOut, double *phaseOut); + void forwardMagnitude(double *realIn, double *magOut); + + void forward(float *realIn, float *realOut, float *imagOut); + void forwardPolar(float *realIn, float *magOut, float *phaseOut); + void forwardMagnitude(float *realIn, float *magOut); + + void inverse(double *realIn, double *imagIn, double *realOut); + void inversePolar(double *magIn, double *phaseIn, double *realOut); + + void inverse(float *realIn, float *imagIn, float *realOut); + void inversePolar(float *magIn, float *phaseIn, float *realOut); + + // Calling one or both of these is optional -- if neither is + // called, the first call to a forward or inverse method will call + // init(). You only need call these if you don't want to risk + // expensive allocations etc happening in forward or inverse. + void initFloat(); + void initDouble(); + + float *getFloatTimeBuffer(); + double *getDoubleTimeBuffer(); + + static void tune(); + +protected: + FFTImpl *d; + static int m_method; +}; + +} + +#endif + diff --git a/libs/rubberband/1.0/src/HighFrequencyAudioCurve.cpp b/libs/rubberband/1.0/src/HighFrequencyAudioCurve.cpp new file mode 100644 index 0000000000..1bc439944d --- /dev/null +++ b/libs/rubberband/1.0/src/HighFrequencyAudioCurve.cpp @@ -0,0 +1,53 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "HighFrequencyAudioCurve.h" + +namespace RubberBand +{ + +HighFrequencyAudioCurve::HighFrequencyAudioCurve(size_t sampleRate, size_t windowSize) : + AudioCurve(sampleRate, windowSize) +{ +} + +HighFrequencyAudioCurve::~HighFrequencyAudioCurve() +{ +} + +void +HighFrequencyAudioCurve::reset() +{ +} + +void +HighFrequencyAudioCurve::setWindowSize(size_t newSize) +{ + m_windowSize = newSize; +} + +float +HighFrequencyAudioCurve::process(float *mag, size_t increment) +{ + float result = 0.0; + + for (size_t n = 0; n <= m_windowSize / 2; ++n) { + result += mag[n] * n; + } + + return result; +} + +} + diff --git a/libs/rubberband/1.0/src/HighFrequencyAudioCurve.h b/libs/rubberband/1.0/src/HighFrequencyAudioCurve.h new file mode 100644 index 0000000000..e891afa930 --- /dev/null +++ b/libs/rubberband/1.0/src/HighFrequencyAudioCurve.h @@ -0,0 +1,39 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _HIGHFREQUENCY_AUDIO_CURVE_H_ +#define _HIGHFREQUENCY_AUDIO_CURVE_H_ + +#include "AudioCurve.h" +#include "Window.h" + +namespace RubberBand +{ + +class HighFrequencyAudioCurve : public AudioCurve +{ +public: + HighFrequencyAudioCurve(size_t sampleRate, size_t windowSize); + + virtual ~HighFrequencyAudioCurve(); + + virtual void setWindowSize(size_t newSize); + + virtual float process(float *mag, size_t increment); + virtual void reset(); +}; + +} + +#endif diff --git a/libs/rubberband/1.0/src/PercussiveAudioCurve.cpp b/libs/rubberband/1.0/src/PercussiveAudioCurve.cpp new file mode 100644 index 0000000000..98c65086d5 --- /dev/null +++ b/libs/rubberband/1.0/src/PercussiveAudioCurve.cpp @@ -0,0 +1,78 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "PercussiveAudioCurve.h" + +#include <cmath> + +namespace RubberBand +{ + +PercussiveAudioCurve::PercussiveAudioCurve(size_t sampleRate, size_t windowSize) : + AudioCurve(sampleRate, windowSize) +{ + m_prevMag = new double[m_windowSize/2 + 1]; + + for (size_t i = 0; i <= m_windowSize/2; ++i) { + m_prevMag[i] = 0.f; + } +} + +PercussiveAudioCurve::~PercussiveAudioCurve() +{ + delete[] m_prevMag; +} + +void +PercussiveAudioCurve::reset() +{ + for (size_t i = 0; i <= m_windowSize/2; ++i) { + m_prevMag[i] = 0; + } +} + +void +PercussiveAudioCurve::setWindowSize(size_t newSize) +{ + delete[] m_prevMag; + m_windowSize = newSize; + + m_prevMag = new double[m_windowSize/2 + 1]; + + reset(); +} + +float +PercussiveAudioCurve::process(float *mag, size_t increment) +{ + static float threshold = pow(10, 0.3); + static float zeroThresh = pow(10, -16); + + size_t count = 0; + size_t nonZeroCount = 0; + + for (size_t n = 1; n <= m_windowSize / 2; ++n) { + float sqrmag = mag[n] * mag[n]; + bool above = ((sqrmag / m_prevMag[n]) >= threshold); + if (above) ++count; + if (sqrmag > zeroThresh) ++nonZeroCount; + m_prevMag[n] = sqrmag; + } + + if (nonZeroCount == 0) return 0; + else return float(count) / float(nonZeroCount); +} + +} + diff --git a/libs/rubberband/1.0/src/PercussiveAudioCurve.h b/libs/rubberband/1.0/src/PercussiveAudioCurve.h new file mode 100644 index 0000000000..1d23a5068d --- /dev/null +++ b/libs/rubberband/1.0/src/PercussiveAudioCurve.h @@ -0,0 +1,41 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _PERCUSSIVE_AUDIO_CURVE_H_ +#define _PERCUSSIVE_AUDIO_CURVE_H_ + +#include "AudioCurve.h" + +namespace RubberBand +{ + +class PercussiveAudioCurve : public AudioCurve +{ +public: + PercussiveAudioCurve(size_t sampleRate, size_t windowSize); + + virtual ~PercussiveAudioCurve(); + + virtual void setWindowSize(size_t newSize); + + virtual float process(float *mag, size_t increment); + virtual void reset(); + +protected: + double *m_prevMag; +}; + +} + +#endif diff --git a/libs/rubberband/1.0/src/Resampler.cpp b/libs/rubberband/1.0/src/Resampler.cpp new file mode 100644 index 0000000000..731ac4ee38 --- /dev/null +++ b/libs/rubberband/1.0/src/Resampler.cpp @@ -0,0 +1,169 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "Resampler.h" + +#include <cstdlib> +#include <cmath> + +#include <iostream> + + +#include <samplerate.h> + +namespace RubberBand { + +class Resampler::D +{ +public: + D(Quality quality, size_t channels, size_t maxBufferSize); + ~D(); + + size_t resample(float **in, float **out, + size_t incount, float ratio, bool final); + + void reset(); + +protected: + SRC_STATE *m_src; + float *m_iin; + float *m_iout; + size_t m_channels; + size_t m_iinsize; + size_t m_ioutsize; +}; + +Resampler::D::D(Quality quality, size_t channels, size_t maxBufferSize) : + m_src(0), + m_iin(0), + m_iout(0), + m_channels(channels), + m_iinsize(0), + m_ioutsize(0) +{ +// std::cerr << "Resampler::Resampler: using libsamplerate implementation" +// << std::endl; + + int err = 0; + m_src = src_new(quality == Best ? SRC_SINC_BEST_QUALITY : + quality == Fastest ? SRC_LINEAR : + SRC_SINC_FASTEST, + channels, &err); + + //!!! check err, throw + + if (maxBufferSize > 0 && m_channels > 1) { + //!!! alignment? + m_iinsize = maxBufferSize * m_channels; + m_ioutsize = maxBufferSize * m_channels * 2; + m_iin = (float *)malloc(m_iinsize * sizeof(float)); + m_iout = (float *)malloc(m_ioutsize * sizeof(float)); + } +} + +Resampler::D::~D() +{ + src_delete(m_src); + if (m_iinsize > 0) { + free(m_iin); + } + if (m_ioutsize > 0) { + free(m_iout); + } +} + +size_t +Resampler::D::resample(float **in, float **out, size_t incount, float ratio, + bool final) +{ + SRC_DATA data; + + size_t outcount = lrintf(ceilf(incount * ratio)); + + if (m_channels == 1) { + data.data_in = *in; + data.data_out = *out; + } else { + if (incount * m_channels > m_iinsize) { + m_iinsize = incount * m_channels; + m_iin = (float *)realloc(m_iin, m_iinsize * sizeof(float)); + } + if (outcount * m_channels > m_ioutsize) { + m_ioutsize = outcount * m_channels; + m_iout = (float *)realloc(m_iout, m_ioutsize * sizeof(float)); + } + for (size_t i = 0; i < incount; ++i) { + for (size_t c = 0; c < m_channels; ++c) { + m_iin[i * m_channels + c] = in[c][i]; + } + } + data.data_in = m_iin; + data.data_out = m_iout; + } + + data.input_frames = incount; + data.output_frames = outcount; + data.src_ratio = ratio; + data.end_of_input = (final ? 1 : 0); + + int err = src_process(m_src, &data); + + //!!! check err, respond appropriately + + if (m_channels > 1) { + for (int i = 0; i < data.output_frames_gen; ++i) { + for (size_t c = 0; c < m_channels; ++c) { + out[c][i] = m_iout[i * m_channels + c]; + } + } + } + + return data.output_frames_gen; +} + +void +Resampler::D::reset() +{ + src_reset(m_src); +} + +} // end namespace + + +namespace RubberBand { + +Resampler::Resampler(Quality quality, size_t channels, size_t maxBufferSize) +{ + m_d = new D(quality, channels, maxBufferSize); +} + +Resampler::~Resampler() +{ + delete m_d; +} + +size_t +Resampler::resample(float **in, float **out, + size_t incount, float ratio, bool final) +{ + return m_d->resample(in, out, incount, ratio, final); +} + +void +Resampler::reset() +{ + m_d->reset(); +} + +} diff --git a/libs/rubberband/1.0/src/Resampler.h b/libs/rubberband/1.0/src/Resampler.h new file mode 100644 index 0000000000..bc07c585da --- /dev/null +++ b/libs/rubberband/1.0/src/Resampler.h @@ -0,0 +1,48 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_RESAMPLER_H_ +#define _RUBBERBAND_RESAMPLER_H_ + +#include <sys/types.h> + +namespace RubberBand { + +class Resampler +{ +public: + enum Quality { Best, FastestTolerable, Fastest }; + + /** + * Construct a resampler with the given quality level and channel + * count. maxBufferSize gives a bound on the maximum incount size + * that may be passed to the resample function before the + * resampler needs to reallocate its internal buffers. + */ + Resampler(Quality quality, size_t channels, size_t maxBufferSize = 0); + ~Resampler(); + + size_t resample(float **in, float **out, + size_t incount, float ratio, bool final = false); + + void reset(); + +protected: + class D; + D *m_d; +}; + +} + +#endif diff --git a/libs/rubberband/1.0/src/RingBuffer.h b/libs/rubberband/1.0/src/RingBuffer.h new file mode 100644 index 0000000000..a3673d32f2 --- /dev/null +++ b/libs/rubberband/1.0/src/RingBuffer.h @@ -0,0 +1,636 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_RINGBUFFER_H_ +#define _RUBBERBAND_RINGBUFFER_H_ + +#include <sys/types.h> + +#ifndef _WIN32 +#include <sys/mman.h> +#endif + +#include "Scavenger.h" + +//#define DEBUG_RINGBUFFER 1 + +#ifdef _WIN32 +#define MLOCK(a,b) 1 +#define MUNLOCK(a,b) 1 +#else +#define MLOCK(a,b) ::mlock(a,b) +#define MUNLOCK(a,b) ::munlock(a,b) +#endif + +#ifdef DEBUG_RINGBUFFER +#include <iostream> +#endif + +namespace RubberBand { + +/** + * RingBuffer implements a lock-free ring buffer for one writer and N + * readers, that is to be used to store a sample type T. + */ + +template <typename T, int N = 1> +class RingBuffer +{ +public: + /** + * Create a ring buffer with room to write n samples. + * + * Note that the internal storage size will actually be n+1 + * samples, as one element is unavailable for administrative + * reasons. Since the ring buffer performs best if its size is a + * power of two, this means n should ideally be some power of two + * minus one. + */ + RingBuffer(size_t n); + + virtual ~RingBuffer(); + + /** + * Return the total capacity of the ring buffer in samples. + * (This is the argument n passed to the constructor.) + */ + size_t getSize() const; + + /** + * Resize the ring buffer. This also empties it; use resized() + * below if you do not want this to happen. Actually swaps in a + * new, larger buffer; the old buffer is scavenged after a seemly + * delay. Should be called from the write thread. + */ + void resize(size_t newSize); + + /** + * Return a new ring buffer (allocated with "new" -- called must + * delete when no longer needed) of the given size, containing the + * same data as this one. If another thread reads from or writes + * to this buffer during the call, the results may be incomplete + * or inconsistent. If this buffer's data will not fit in the new + * size, the contents are undefined. + */ + RingBuffer<T, N> *resized(size_t newSize, int R = 0) const; + + /** + * Lock the ring buffer into physical memory. Returns true + * for success. + */ + bool mlock(); + + /** + * Reset read and write pointers, thus emptying the buffer. + * Should be called from the write thread. + */ + void reset(); + + /** + * Return the amount of data available for reading by reader R, in + * samples. + */ + size_t getReadSpace(int R = 0) const; + + /** + * Return the amount of space available for writing, in samples. + */ + size_t getWriteSpace() const; + + /** + * Read n samples from the buffer, for reader R. If fewer than n + * are available, the remainder will be zeroed out. Returns the + * number of samples actually read. + */ + size_t read(T *destination, size_t n, int R = 0); + + /** + * Read n samples from the buffer, for reader R, adding them to + * the destination. If fewer than n are available, the remainder + * will be left alone. Returns the number of samples actually + * read. + */ + size_t readAdding(T *destination, size_t n, int R = 0); + + /** + * Read one sample from the buffer, for reader R. If no sample is + * available, this will silently return zero. Calling this + * repeatedly is obviously slower than calling read once, but it + * may be good enough if you don't want to allocate a buffer to + * read into. + */ + T readOne(int R = 0); + + /** + * Read n samples from the buffer, if available, for reader R, + * without advancing the read pointer -- i.e. a subsequent read() + * or skip() will be necessary to empty the buffer. If fewer than + * n are available, the remainder will be zeroed out. Returns the + * number of samples actually read. + */ + size_t peek(T *destination, size_t n, int R = 0) const; + + /** + * Read one sample from the buffer, if available, without + * advancing the read pointer -- i.e. a subsequent read() or + * skip() will be necessary to empty the buffer. Returns zero if + * no sample was available. + */ + T peekOne(int R = 0) const; + + /** + * Pretend to read n samples from the buffer, for reader R, + * without actually returning them (i.e. discard the next n + * samples). Returns the number of samples actually available for + * discarding. + */ + size_t skip(size_t n, int R = 0); + + /** + * Write n samples to the buffer. If insufficient space is + * available, not all samples may actually be written. Returns + * the number of samples actually written. + */ + size_t write(const T *source, size_t n); + + /** + * Write n zero-value samples to the buffer. If insufficient + * space is available, not all zeros may actually be written. + * Returns the number of zeroes actually written. + */ + size_t zero(size_t n); + +protected: + T *m_buffer; + volatile size_t m_writer; + volatile size_t m_readers[N]; + size_t m_size; + bool m_mlocked; + + static Scavenger<ScavengerArrayWrapper<T> > m_scavenger; + +private: + RingBuffer(const RingBuffer &); // not provided + RingBuffer &operator=(const RingBuffer &); // not provided +}; + +template <typename T, int N> +Scavenger<ScavengerArrayWrapper<T> > RingBuffer<T, N>::m_scavenger; + +template <typename T, int N> +RingBuffer<T, N>::RingBuffer(size_t n) : + m_buffer(new T[n + 1]), + m_writer(0), + m_size(n + 1), + m_mlocked(false) +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::RingBuffer(" << n << ")" << std::endl; +#endif + + for (int i = 0; i < N; ++i) m_readers[i] = 0; + + m_scavenger.scavenge(); +} + +template <typename T, int N> +RingBuffer<T, N>::~RingBuffer() +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::~RingBuffer" << std::endl; +#endif + + if (m_mlocked) { + MUNLOCK((void *)m_buffer, m_size * sizeof(T)); + } + delete[] m_buffer; + + m_scavenger.scavenge(); +} + +template <typename T, int N> +size_t +RingBuffer<T, N>::getSize() const +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getSize(): " << m_size-1 << std::endl; +#endif + + return m_size - 1; +} + +template <typename T, int N> +void +RingBuffer<T, N>::resize(size_t newSize) +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::resize(" << newSize << ")" << std::endl; +#endif + + m_scavenger.scavenge(); + + if (m_mlocked) { + MUNLOCK((void *)m_buffer, m_size * sizeof(T)); + } + + m_scavenger.claim(new ScavengerArrayWrapper<T>(m_buffer)); + + reset(); + m_buffer = new T[newSize + 1]; + m_size = newSize + 1; + + if (m_mlocked) { + if (MLOCK((void *)m_buffer, m_size * sizeof(T))) { + m_mlocked = false; + } + } +} + +template <typename T, int N> +RingBuffer<T, N> * +RingBuffer<T, N>::resized(size_t newSize, int R) const +{ + RingBuffer<T, N> *newBuffer = new RingBuffer<T, N>(newSize); + + size_t w = m_writer; + size_t r = m_readers[R]; + + while (r != w) { + T value = m_buffer[r]; + newBuffer->write(&value, 1); + if (++r == m_size) r = 0; + } + + return newBuffer; +} + +template <typename T, int N> +bool +RingBuffer<T, N>::mlock() +{ + if (MLOCK((void *)m_buffer, m_size * sizeof(T))) return false; + m_mlocked = true; + return true; +} + +template <typename T, int N> +void +RingBuffer<T, N>::reset() +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::reset" << std::endl; +#endif + + m_writer = 0; + for (int i = 0; i < N; ++i) m_readers[i] = 0; +} + +template <typename T, int N> +size_t +RingBuffer<T, N>::getReadSpace(int R) const +{ + size_t writer = m_writer; + size_t reader = m_readers[R]; + size_t space; + +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getReadSpace(" << R << "): reader " << reader << ", writer " << writer << std::endl; +#endif + + if (writer > reader) space = writer - reader; + else if (writer < reader) space = (writer + m_size) - reader; + else space = 0; + +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getReadSpace(" << R << "): " << space << std::endl; +#endif + + return space; +} + +template <typename T, int N> +size_t +RingBuffer<T, N>::getWriteSpace() const +{ + size_t space = 0; + for (int i = 0; i < N; ++i) { + size_t writer = m_writer; + size_t reader = m_readers[i]; + size_t here = (reader + m_size - writer - 1); + if (here >= m_size) here -= m_size; + if (i == 0 || here < space) space = here; + } + +#ifdef DEBUG_RINGBUFFER + size_t rs(getReadSpace()), rp(m_readers[0]); + + std::cerr << "RingBuffer: write space " << space << ", read space " + << rs << ", total " << (space + rs) << ", m_size " << m_size << std::endl; + std::cerr << "RingBuffer: reader " << rp << ", writer " << m_writer << std::endl; +#endif + +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getWriteSpace(): " << space << std::endl; +#endif + + return space; +} + +template <typename T, int N> +size_t +RingBuffer<T, N>::read(T *destination, size_t n, int R) +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read(dest, " << n << ", " << R << ")" << std::endl; +#endif + + size_t available = getReadSpace(R); + if (n > available) { +#ifdef DEBUG_RINGBUFFER + std::cerr << "WARNING: Only " << available << " samples available" + << std::endl; +#endif + for (size_t i = available; i < n; ++i) { + destination[i] = 0; + } + n = available; + } + if (n == 0) return n; + + size_t reader = m_readers[R]; + size_t here = m_size - reader; + + if (here >= n) { + for (size_t i = 0; i < n; ++i) { + destination[i] = (m_buffer + reader)[i]; + } + } else { + for (size_t i = 0; i < here; ++i) { + destination[i] = (m_buffer + reader)[i]; + } + for (size_t i = 0; i < (n - here); ++i) { + destination[i + here] = m_buffer[i]; + } + } + + reader += n; + while (reader >= m_size) reader -= m_size; + m_readers[R] = reader; + +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read: read " << n << ", reader now " << m_readers[R] << std::endl; +#endif + + return n; +} + +template <typename T, int N> +size_t +RingBuffer<T, N>::readAdding(T *destination, size_t n, int R) +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readAdding(dest, " << n << ", " << R << ")" << std::endl; +#endif + + size_t available = getReadSpace(R); + if (n > available) { +#ifdef DEBUG_RINGBUFFER + std::cerr << "WARNING: Only " << available << " samples available" + << std::endl; +#endif + n = available; + } + if (n == 0) return n; + + size_t reader = m_readers[R]; + size_t here = m_size - reader; + + if (here >= n) { + for (size_t i = 0; i < n; ++i) { + destination[i] += (m_buffer + reader)[i]; + } + } else { + for (size_t i = 0; i < here; ++i) { + destination[i] += (m_buffer + reader)[i]; + } + for (size_t i = 0; i < (n - here); ++i) { + destination[i + here] += m_buffer[i]; + } + } + + reader += n; + while (reader >= m_size) reader -= m_size; + m_readers[R] = reader; + return n; +} + +template <typename T, int N> +T +RingBuffer<T, N>::readOne(int R) +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readOne(" << R << ")" << std::endl; +#endif + + if (m_writer == m_readers[R]) { +#ifdef DEBUG_RINGBUFFER + std::cerr << "WARNING: No sample available" + << std::endl; +#endif + return 0; + } + size_t reader = m_readers[R]; + T value = m_buffer[reader]; + if (++reader == m_size) reader = 0; + m_readers[R] = reader; + return value; +} + +template <typename T, int N> +size_t +RingBuffer<T, N>::peek(T *destination, size_t n, int R) const +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(dest, " << n << ", " << R << ")" << std::endl; +#endif + + size_t available = getReadSpace(R); + if (n > available) { +#ifdef DEBUG_RINGBUFFER + std::cerr << "WARNING: Only " << available << " samples available" + << std::endl; +#endif + memset(destination + available, 0, (n - available) * sizeof(T)); + n = available; + } + if (n == 0) return n; + + size_t reader = m_readers[R]; + size_t here = m_size - reader; + + if (here >= n) { + for (size_t i = 0; i < n; ++i) { + destination[i] = (m_buffer + reader)[i]; + } + } else { + for (size_t i = 0; i < here; ++i) { + destination[i] = (m_buffer + reader)[i]; + } + for (size_t i = 0; i < (n - here); ++i) { + destination[i + here] = m_buffer[i]; + } + } + +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek: read " << n << std::endl; +#endif + + return n; +} + +template <typename T, int N> +T +RingBuffer<T, N>::peekOne(int R) const +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(" << R << ")" << std::endl; +#endif + + if (m_writer == m_readers[R]) { +#ifdef DEBUG_RINGBUFFER + std::cerr << "WARNING: No sample available" + << std::endl; +#endif + return 0; + } + T value = m_buffer[m_readers[R]]; + return value; +} + +template <typename T, int N> +size_t +RingBuffer<T, N>::skip(size_t n, int R) +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::skip(" << n << ", " << R << ")" << std::endl; +#endif + + size_t available = getReadSpace(R); + if (n > available) { +#ifdef DEBUG_RINGBUFFER + std::cerr << "WARNING: Only " << available << " samples available" + << std::endl; +#endif + n = available; + } + if (n == 0) return n; + + size_t reader = m_readers[R]; + reader += n; + while (reader >= m_size) reader -= m_size; + m_readers[R] = reader; + return n; +} + +template <typename T, int N> +size_t +RingBuffer<T, N>::write(const T *source, size_t n) +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write(" << n << ")" << std::endl; +#endif + + size_t available = getWriteSpace(); + if (n > available) { +#ifdef DEBUG_RINGBUFFER + std::cerr << "WARNING: Only room for " << available << " samples" + << std::endl; +#endif + n = available; + } + if (n == 0) return n; + + size_t writer = m_writer; + size_t here = m_size - writer; + if (here >= n) { + for (size_t i = 0; i < n; ++i) { + (m_buffer + writer)[i] = source[i]; + } + } else { + for (size_t i = 0; i < here; ++i) { + (m_buffer + writer)[i] = source[i]; + } + for (size_t i = 0; i < (n - here); ++i) { + m_buffer[i] = (source + here)[i]; + } + } + + writer += n; + while (writer >= m_size) writer -= m_size; + m_writer = writer; + +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write: wrote " << n << ", writer now " << m_writer << std::endl; +#endif + + return n; +} + +template <typename T, int N> +size_t +RingBuffer<T, N>::zero(size_t n) +{ +#ifdef DEBUG_RINGBUFFER + std::cerr << "RingBuffer<T," << N << ">[" << this << "]::zero(" << n << ")" << std::endl; +#endif + + size_t available = getWriteSpace(); + if (n > available) { +#ifdef DEBUG_RINGBUFFER + std::cerr << "WARNING: Only room for " << available << " samples" + << std::endl; +#endif + n = available; + } + if (n == 0) return n; + + size_t writer = m_writer; + size_t here = m_size - writer; + if (here >= n) { + for (size_t i = 0; i < n; ++i) { + (m_buffer + writer)[i] = 0; + } + } else { + for (size_t i = 0; i < here; ++i) { + (m_buffer + writer)[i] = 0; + } + for (size_t i = 0; i < (n - here); ++i) { + m_buffer[i] = 0; + } + } + + writer += n; + while (writer >= m_size) writer -= m_size; + m_writer = writer; + +#ifdef DEBUG_RINGBUFFER + std::cerr << "writer -> " << m_writer << std::endl; +#endif + + return n; +} + +} + +#endif // _RINGBUFFER_H_ diff --git a/libs/rubberband/1.0/src/RubberBandStretcher.cpp b/libs/rubberband/1.0/src/RubberBandStretcher.cpp new file mode 100644 index 0000000000..9a401b4e43 --- /dev/null +++ b/libs/rubberband/1.0/src/RubberBandStretcher.cpp @@ -0,0 +1,189 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "StretcherImpl.h" + +namespace RubberBand { + + +RubberBandStretcher::RubberBandStretcher(size_t sampleRate, + size_t channels, + Options options, + double initialTimeRatio, + double initialPitchScale) : + TimeStretcher(sampleRate, channels), + m_d(new Impl(this, sampleRate, channels, options, + initialTimeRatio, initialPitchScale)) +{ +} + +RubberBandStretcher::~RubberBandStretcher() +{ + delete m_d; +} + +void +RubberBandStretcher::reset() +{ + m_d->reset(); +} + +void +RubberBandStretcher::setTimeRatio(double ratio) +{ + m_d->setTimeRatio(ratio); +} + +void +RubberBandStretcher::setPitchScale(double scale) +{ + m_d->setPitchScale(scale); +} + +double +RubberBandStretcher::getTimeRatio() const +{ + return m_d->getTimeRatio(); +} + +double +RubberBandStretcher::getPitchScale() const +{ + return m_d->getPitchScale(); +} + +size_t +RubberBandStretcher::getLatency() const +{ + return m_d->getLatency(); +} + +void +RubberBandStretcher::setTransientsOption(Options options) +{ + m_d->setTransientsOption(options); +} + +void +RubberBandStretcher::setPhaseOption(Options options) +{ + m_d->setPhaseOption(options); +} + +void +RubberBandStretcher::setExpectedInputDuration(size_t samples) +{ + m_d->setExpectedInputDuration(samples); +} + +void +RubberBandStretcher::setMaxProcessSize(size_t samples) +{ + m_d->setMaxProcessSize(samples); +} + +size_t +RubberBandStretcher::getSamplesRequired() const +{ + return m_d->getSamplesRequired(); +} + +void +RubberBandStretcher::study(const float *const *input, size_t samples, + bool final) +{ + m_d->study(input, samples, final); +} + +void +RubberBandStretcher::process(const float *const *input, size_t samples, + bool final) +{ + m_d->process(input, samples, final); +} + +int +RubberBandStretcher::available() const +{ + return m_d->available(); +} + +size_t +RubberBandStretcher::retrieve(float *const *output, size_t samples) const +{ + return m_d->retrieve(output, samples); +} + +float +RubberBandStretcher::getFrequencyCutoff(int n) const +{ + return m_d->getFrequencyCutoff(n); +} + +void +RubberBandStretcher::setFrequencyCutoff(int n, float f) +{ + m_d->setFrequencyCutoff(n, f); +} + +size_t +RubberBandStretcher::getInputIncrement() const +{ + return m_d->getInputIncrement(); +} + +std::vector<int> +RubberBandStretcher::getOutputIncrements() const +{ + return m_d->getOutputIncrements(); +} + +std::vector<float> +RubberBandStretcher::getPhaseResetCurve() const +{ + return m_d->getPhaseResetCurve(); +} + +std::vector<int> +RubberBandStretcher::getExactTimePoints() const +{ + return m_d->getExactTimePoints(); +} + +size_t +RubberBandStretcher::getChannelCount() const +{ + return m_d->getChannelCount(); +} + +void +RubberBandStretcher::calculateStretch() +{ + m_d->calculateStretch(); +} + +void +RubberBandStretcher::setDebugLevel(int level) +{ + m_d->setDebugLevel(level); +} + +void +RubberBandStretcher::setDefaultDebugLevel(int level) +{ + Impl::setDefaultDebugLevel(level); +} + +} + diff --git a/libs/rubberband/1.0/src/Scavenger.h b/libs/rubberband/1.0/src/Scavenger.h new file mode 100644 index 0000000000..54af5dab0c --- /dev/null +++ b/libs/rubberband/1.0/src/Scavenger.h @@ -0,0 +1,199 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_SCAVENGER_H_ +#define _RUBBERBAND_SCAVENGER_H_ + +#include <vector> +#include <list> +#include <sys/time.h> +#include <iostream> + +#include "Thread.h" +#include "sysutils.h" + +namespace RubberBand { + +/** + * A very simple class that facilitates running things like plugins + * without locking, by collecting unwanted objects and deleting them + * after a delay so as to be sure nobody's in the middle of using + * them. Requires scavenge() to be called regularly from a non-RT + * thread. + * + * This is currently not at all suitable for large numbers of objects + * -- it's just a quick hack for use with things like plugins. + */ + +template <typename T> +class Scavenger +{ +public: + Scavenger(int sec = 2, int defaultObjectListSize = 200); + ~Scavenger(); + + /** + * Call from an RT thread etc., to pass ownership of t to us. + * Only one thread should be calling this on any given scavenger. + */ + void claim(T *t); + + /** + * Call from a non-RT thread. + * Only one thread should be calling this on any given scavenger. + */ + void scavenge(bool clearNow = false); + +protected: + typedef std::pair<T *, int> ObjectTimePair; + typedef std::vector<ObjectTimePair> ObjectTimeList; + ObjectTimeList m_objects; + int m_sec; + + typedef std::list<T *> ObjectList; + ObjectList m_excess; + int m_lastExcess; + Mutex m_excessMutex; + void pushExcess(T *); + void clearExcess(int); + + unsigned int m_claimed; + unsigned int m_scavenged; +}; + +/** + * A wrapper to permit arrays to be scavenged. + */ + +template <typename T> +class ScavengerArrayWrapper +{ +public: + ScavengerArrayWrapper(T *array) : m_array(array) { } + ~ScavengerArrayWrapper() { delete[] m_array; } + +private: + T *m_array; +}; + + +template <typename T> +Scavenger<T>::Scavenger(int sec, int defaultObjectListSize) : + m_objects(ObjectTimeList(defaultObjectListSize)), + m_sec(sec), + m_claimed(0), + m_scavenged(0) +{ +} + +template <typename T> +Scavenger<T>::~Scavenger() +{ + if (m_scavenged < m_claimed) { + for (size_t i = 0; i < m_objects.size(); ++i) { + ObjectTimePair &pair = m_objects[i]; + if (pair.first != 0) { + T *ot = pair.first; + pair.first = 0; + delete ot; + ++m_scavenged; + } + } + } + + clearExcess(0); +} + +template <typename T> +void +Scavenger<T>::claim(T *t) +{ +// std::cerr << "Scavenger::claim(" << t << ")" << std::endl; + + struct timeval tv; + (void)gettimeofday(&tv, 0); + int sec = tv.tv_sec; + + for (size_t i = 0; i < m_objects.size(); ++i) { + ObjectTimePair &pair = m_objects[i]; + if (pair.first == 0) { + pair.second = sec; + pair.first = t; + ++m_claimed; + return; + } + } + + std::cerr << "WARNING: Scavenger::claim(" << t << "): run out of slots, " + << "using non-RT-safe method" << std::endl; + pushExcess(t); +} + +template <typename T> +void +Scavenger<T>::scavenge(bool clearNow) +{ +// std::cerr << "Scavenger::scavenge: scavenged " << m_scavenged << ", claimed " << m_claimed << std::endl; + + if (m_scavenged >= m_claimed) return; + + struct timeval tv; + (void)gettimeofday(&tv, 0); + int sec = tv.tv_sec; + + for (size_t i = 0; i < m_objects.size(); ++i) { + ObjectTimePair &pair = m_objects[i]; + if (clearNow || + (pair.first != 0 && pair.second + m_sec < sec)) { + T *ot = pair.first; + pair.first = 0; + delete ot; + ++m_scavenged; + } + } + + if (sec > m_lastExcess + m_sec) { + clearExcess(sec); + } +} + +template <typename T> +void +Scavenger<T>::pushExcess(T *t) +{ + m_excessMutex.lock(); + m_excess.push_back(t); + struct timeval tv; + (void)gettimeofday(&tv, 0); + m_lastExcess = tv.tv_sec; + m_excessMutex.unlock(); +} + +template <typename T> +void +Scavenger<T>::clearExcess(int sec) +{ + m_excessMutex.lock(); + for (typename ObjectList::iterator i = m_excess.begin(); + i != m_excess.end(); ++i) { + delete *i; + } + m_excess.clear(); + m_lastExcess = sec; + m_excessMutex.unlock(); +} + +} + +#endif diff --git a/libs/rubberband/1.0/src/SpectralDifferenceAudioCurve.cpp b/libs/rubberband/1.0/src/SpectralDifferenceAudioCurve.cpp new file mode 100644 index 0000000000..fe26e3e357 --- /dev/null +++ b/libs/rubberband/1.0/src/SpectralDifferenceAudioCurve.cpp @@ -0,0 +1,64 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "SpectralDifferenceAudioCurve.h" + +namespace RubberBand +{ + +SpectralDifferenceAudioCurve::SpectralDifferenceAudioCurve(size_t sampleRate, size_t windowSize) : + AudioCurve(sampleRate, windowSize) +{ + m_prevMag = new double[m_windowSize/2 + 1]; + + for (size_t i = 0; i <= m_windowSize/2; ++i) { + m_prevMag[i] = 0.f; + } +} + +SpectralDifferenceAudioCurve::~SpectralDifferenceAudioCurve() +{ + delete[] m_prevMag; +} + +void +SpectralDifferenceAudioCurve::reset() +{ + for (size_t i = 0; i <= m_windowSize/2; ++i) { + m_prevMag[i] = 0; + } +} + +void +SpectralDifferenceAudioCurve::setWindowSize(size_t newSize) +{ + m_windowSize = newSize; +} + +float +SpectralDifferenceAudioCurve::process(float *mag, size_t increment) +{ + float result = 0.0; + + for (size_t n = 0; n <= m_windowSize / 2; ++n) { + result += sqrtf(fabsf((mag[n] * mag[n]) - + (m_prevMag[n] * m_prevMag[n]))); + m_prevMag[n] = mag[n]; + } + + return result; +} + +} + diff --git a/libs/rubberband/1.0/src/SpectralDifferenceAudioCurve.h b/libs/rubberband/1.0/src/SpectralDifferenceAudioCurve.h new file mode 100644 index 0000000000..c6f4484d43 --- /dev/null +++ b/libs/rubberband/1.0/src/SpectralDifferenceAudioCurve.h @@ -0,0 +1,42 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _SPECTRALDIFFERENCE_AUDIO_CURVE_H_ +#define _SPECTRALDIFFERENCE_AUDIO_CURVE_H_ + +#include "AudioCurve.h" +#include "Window.h" + +namespace RubberBand +{ + +class SpectralDifferenceAudioCurve : public AudioCurve +{ +public: + SpectralDifferenceAudioCurve(size_t sampleRate, size_t windowSize); + + virtual ~SpectralDifferenceAudioCurve(); + + virtual void setWindowSize(size_t newSize); + + virtual float process(float *mag, size_t increment); + virtual void reset(); + +protected: + double *m_prevMag; +}; + +} + +#endif diff --git a/libs/rubberband/1.0/src/StretchCalculator.cpp b/libs/rubberband/1.0/src/StretchCalculator.cpp new file mode 100644 index 0000000000..77d1c50ddf --- /dev/null +++ b/libs/rubberband/1.0/src/StretchCalculator.cpp @@ -0,0 +1,790 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "StretchCalculator.h" + +#include <math.h> +#include <iostream> +#include <deque> +#include <set> +#include <cassert> + +namespace RubberBand +{ + +StretchCalculator::StretchCalculator(size_t sampleRate, + size_t inputIncrement, + bool useHardPeaks) : + m_sampleRate(sampleRate), + m_increment(inputIncrement), + m_prevDf(0), + m_divergence(0), + m_recovery(0), + m_prevRatio(1.0), + m_transientAmnesty(0), + m_useHardPeaks(useHardPeaks) +{ +// std::cerr << "StretchCalculator::StretchCalculator: useHardPeaks = " << useHardPeaks << std::endl; +} + +StretchCalculator::~StretchCalculator() +{ +} + +std::vector<int> +StretchCalculator::calculate(double ratio, size_t inputDuration, + const std::vector<float> &phaseResetDf, + const std::vector<float> &stretchDf) +{ + assert(phaseResetDf.size() == stretchDf.size()); + + m_lastPeaks = findPeaks(phaseResetDf); + std::vector<Peak> &peaks = m_lastPeaks; + size_t totalCount = phaseResetDf.size(); + + std::vector<int> increments; + + size_t outputDuration = lrint(inputDuration * ratio); + + if (m_debugLevel > 0) { + std::cerr << "StretchCalculator::calculate(): inputDuration " << inputDuration << ", ratio " << ratio << ", outputDuration " << outputDuration; + } + + outputDuration = lrint((phaseResetDf.size() * m_increment) * ratio); + + if (m_debugLevel > 0) { + std::cerr << " (rounded up to " << outputDuration << ")"; + std::cerr << ", df size " << phaseResetDf.size() << std::endl; + } + + std::vector<size_t> fixedAudioChunks; + for (size_t i = 0; i < peaks.size(); ++i) { + fixedAudioChunks.push_back + (lrint((double(peaks[i].chunk) * outputDuration) / totalCount)); + } + + if (m_debugLevel > 1) { + std::cerr << "have " << peaks.size() << " fixed positions" << std::endl; + } + + size_t totalInput = 0, totalOutput = 0; + + // For each region between two consecutive time sync points, we + // want to take the number of output chunks to be allocated and + // the detection function values within the range, and produce a + // series of increments that sum to the number of output chunks, + // such that each increment is displaced from the input increment + // by an amount inversely proportional to the magnitude of the + // stretch detection function at that input step. + + size_t regionTotalChunks = 0; + + for (size_t i = 0; i <= peaks.size(); ++i) { + + size_t regionStart, regionStartChunk, regionEnd, regionEndChunk; + bool phaseReset = false; + + if (i == 0) { + regionStartChunk = 0; + regionStart = 0; + } else { + regionStartChunk = peaks[i-1].chunk; + regionStart = fixedAudioChunks[i-1]; + phaseReset = peaks[i-1].hard; + } + + if (i == peaks.size()) { + regionEndChunk = totalCount; + regionEnd = outputDuration; + } else { + regionEndChunk = peaks[i].chunk; + regionEnd = fixedAudioChunks[i]; + } + + size_t regionDuration = regionEnd - regionStart; + regionTotalChunks += regionDuration; + + std::vector<float> dfRegion; + + for (size_t j = regionStartChunk; j != regionEndChunk; ++j) { + dfRegion.push_back(stretchDf[j]); + } + + if (m_debugLevel > 1) { + std::cerr << "distributeRegion from " << regionStartChunk << " to " << regionEndChunk << " (chunks " << regionStart << " to " << regionEnd << ")" << std::endl; + } + + dfRegion = smoothDF(dfRegion); + + std::vector<int> regionIncrements = distributeRegion + (dfRegion, regionDuration, ratio, phaseReset); + + size_t totalForRegion = 0; + + for (size_t j = 0; j < regionIncrements.size(); ++j) { + + int incr = regionIncrements[j]; + + if (j == 0 && phaseReset) increments.push_back(-incr); + else increments.push_back(incr); + + if (incr > 0) totalForRegion += incr; + else totalForRegion += -incr; + + totalInput += m_increment; + } + + if (totalForRegion != regionDuration) { + std::cerr << "*** WARNING: distributeRegion returned wrong duration " << totalForRegion << ", expected " << regionDuration << std::endl; + } + + totalOutput += totalForRegion; + } + + if (m_debugLevel > 0) { + std::cerr << "total input increment = " << totalInput << " (= " << totalInput / m_increment << " chunks), output = " << totalOutput << ", ratio = " << double(totalOutput)/double(totalInput) << ", ideal output " << size_t(ceil(totalInput * ratio)) << std::endl; + std::cerr << "(region total = " << regionTotalChunks << ")" << std::endl; + } + + return increments; +} + +int +StretchCalculator::calculateSingle(double ratio, + size_t inputDurationSoFar, + float df) +{ + bool isTransient = false; + + // We want to ensure, as close as possible, that the phase reset + // points appear at _exactly_ the right audio frame numbers. + + // In principle, the threshold depends on chunk size: larger chunk + // sizes need higher thresholds. Since chunk size depends on + // ratio, I suppose we could in theory calculate the threshold + // from the ratio directly. For the moment we're happy if it + // works well in common situations. + + float transientThreshold = 0.35; + if (ratio > 1) transientThreshold = 0.25; + + if (m_useHardPeaks && df > m_prevDf * 1.1 && df > transientThreshold) { + isTransient = true; + } + + if (m_debugLevel > 2) { + std::cerr << "df = " << df << ", prevDf = " << m_prevDf + << ", thresh = " << transientThreshold << std::endl; + } + + m_prevDf = df; + + if (isTransient && m_transientAmnesty == 0) { + if (m_debugLevel > 1) { + std::cerr << "StretchCalculator::calculateSingle: transient found at " + << inputDurationSoFar << std::endl; + } + m_divergence += m_increment - (m_increment * ratio); + + // as in offline mode, 0.05 sec approx min between transients + m_transientAmnesty = + lrint(ceil(double(m_sampleRate) / (20 * double(m_increment)))); + + m_recovery = m_divergence / ((m_sampleRate / 10.0) / m_increment); + return -m_increment; + } + + if (m_prevRatio != ratio) { + m_recovery = m_divergence / ((m_sampleRate / 10.0) / m_increment); + m_prevRatio = ratio; + } + + if (m_transientAmnesty > 0) --m_transientAmnesty; + + int incr = lrint(m_increment * ratio - m_recovery); + if (m_debugLevel > 2 || (m_debugLevel > 1 && m_divergence != 0)) { + std::cerr << "divergence = " << m_divergence << ", recovery = " << m_recovery << ", incr = " << incr << ", "; + } + if (incr < lrint((m_increment * ratio) / 2)) { + incr = lrint((m_increment * ratio) / 2); + } else if (incr > lrint(m_increment * ratio * 2)) { + incr = lrint(m_increment * ratio * 2); + } + + double divdiff = (m_increment * ratio) - incr; + + if (m_debugLevel > 2 || (m_debugLevel > 1 && m_divergence != 0)) { + std::cerr << "divdiff = " << divdiff << std::endl; + } + + double prevDivergence = m_divergence; + m_divergence -= divdiff; + if ((prevDivergence < 0 && m_divergence > 0) || + (prevDivergence > 0 && m_divergence < 0)) { + m_recovery = m_divergence / ((m_sampleRate / 10.0) / m_increment); + } + + return incr; +} + +void +StretchCalculator::reset() +{ + m_prevDf = 0; + m_divergence = 0; +} + +std::vector<StretchCalculator::Peak> +StretchCalculator::findPeaks(const std::vector<float> &rawDf) +{ + std::vector<float> df = smoothDF(rawDf); + + // We distinguish between "soft" and "hard" peaks. A soft peak is + // simply the result of peak-picking on the smoothed onset + // detection function, and it represents any (strong-ish) onset. + // We aim to ensure always that soft peaks are placed at the + // correct position in time. A hard peak is where there is a very + // rapid rise in detection function, and it presumably represents + // a more broadband, noisy transient. For these we perform a + // phase reset (if in the appropriate mode), and we locate the + // reset at the first point where we notice enough of a rapid + // rise, rather than necessarily at the peak itself, in order to + // preserve the shape of the transient. + + std::set<size_t> hardPeakCandidates; + std::set<size_t> softPeakCandidates; + + if (m_useHardPeaks) { + + // 0.05 sec approx min between hard peaks + size_t hardPeakAmnesty = lrint(ceil(double(m_sampleRate) / + (20 * double(m_increment)))); + size_t prevHardPeak = 0; + + if (m_debugLevel > 1) { + std::cerr << "hardPeakAmnesty = " << hardPeakAmnesty << std::endl; + } + + for (size_t i = 1; i + 1 < df.size(); ++i) { + + if (df[i] < 0.1) continue; + if (df[i] <= df[i-1] * 1.1) continue; + if (df[i] < 0.22) continue; + + if (!hardPeakCandidates.empty() && + i < prevHardPeak + hardPeakAmnesty) { + continue; + } + + bool hard = (df[i] > 0.4); + + if (hard && (m_debugLevel > 1)) { + std::cerr << "hard peak at " << i << ": " << df[i] + << " > absolute " << 0.4 + << std::endl; + } + + if (!hard) { + hard = (df[i] > df[i-1] * 1.4); + + if (hard && (m_debugLevel > 1)) { + std::cerr << "hard peak at " << i << ": " << df[i] + << " > prev " << df[i-1] << " * 1.4" + << std::endl; + } + } + + if (!hard && i > 1) { + hard = (df[i] > df[i-1] * 1.2 && + df[i-1] > df[i-2] * 1.2); + + if (hard && (m_debugLevel > 1)) { + std::cerr << "hard peak at " << i << ": " << df[i] + << " > prev " << df[i-1] << " * 1.2 and " + << df[i-1] << " > prev " << df[i-2] << " * 1.2" + << std::endl; + } + } + + if (!hard && i > 2) { + // have already established that df[i] > df[i-1] * 1.1 + hard = (df[i] > 0.3 && + df[i-1] > df[i-2] * 1.1 && + df[i-2] > df[i-3] * 1.1); + + if (hard && (m_debugLevel > 1)) { + std::cerr << "hard peak at " << i << ": " << df[i] + << " > prev " << df[i-1] << " * 1.1 and " + << df[i-1] << " > prev " << df[i-2] << " * 1.1 and " + << df[i-2] << " > prev " << df[i-3] << " * 1.1" + << std::endl; + } + } + + if (!hard) continue; + +// (df[i+1] > df[i] && df[i+1] > df[i-1] * 1.8) || +// df[i] > 0.4) { + + size_t peakLocation = i; + + if (i + 1 < rawDf.size() && + rawDf[i + 1] > rawDf[i] * 1.4) { + + ++peakLocation; + + if (m_debugLevel > 1) { + std::cerr << "pushing hard peak forward to " << peakLocation << ": " << df[peakLocation] << " > " << df[peakLocation-1] << " * " << 1.4 << std::endl; + } + } + + hardPeakCandidates.insert(peakLocation); + prevHardPeak = peakLocation; + } + } + + size_t medianmaxsize = lrint(ceil(double(m_sampleRate) / + double(m_increment))); // 1 sec ish + + if (m_debugLevel > 1) { + std::cerr << "mediansize = " << medianmaxsize << std::endl; + } + if (medianmaxsize < 7) { + medianmaxsize = 7; + if (m_debugLevel > 1) { + std::cerr << "adjusted mediansize = " << medianmaxsize << std::endl; + } + } + + int minspacing = lrint(ceil(double(m_sampleRate) / + (20 * double(m_increment)))); // 0.05 sec ish + + std::deque<float> medianwin; + std::vector<float> sorted; + int softPeakAmnesty = 0; + + for (size_t i = 0; i < medianmaxsize/2; ++i) { + medianwin.push_back(0); + } + for (size_t i = 0; i < medianmaxsize/2 && i < df.size(); ++i) { + medianwin.push_back(df[i]); + } + + size_t lastSoftPeak = 0; + + for (size_t i = 0; i < df.size(); ++i) { + + size_t mediansize = medianmaxsize; + + if (medianwin.size() < mediansize) { + mediansize = medianwin.size(); + } + + size_t middle = medianmaxsize / 2; + if (middle >= mediansize) middle = mediansize-1; + + size_t nextDf = i + mediansize - middle; + + if (mediansize < 2) { + if (mediansize > medianmaxsize) { // absurd, but never mind that + medianwin.pop_front(); + } + if (nextDf < df.size()) { + medianwin.push_back(df[nextDf]); + } else { + medianwin.push_back(0); + } + continue; + } + + if (m_debugLevel > 2) { +// std::cerr << "have " << mediansize << " in median buffer" << std::endl; + } + + sorted.clear(); + for (size_t j = 0; j < mediansize; ++j) { + sorted.push_back(medianwin[j]); + } + std::sort(sorted.begin(), sorted.end()); + + size_t n = 90; // percentile above which we pick peaks + size_t index = (sorted.size() * n) / 100; + if (index >= sorted.size()) index = sorted.size()-1; + if (index == sorted.size()-1 && index > 0) --index; + float thresh = sorted[index]; + +// if (m_debugLevel > 2) { +// std::cerr << "medianwin[" << middle << "] = " << medianwin[middle] << ", thresh = " << thresh << std::endl; +// if (medianwin[middle] == 0.f) { +// std::cerr << "contents: "; +// for (size_t j = 0; j < medianwin.size(); ++j) { +// std::cerr << medianwin[j] << " "; +// } +// std::cerr << std::endl; +// } +// } + + if (medianwin[middle] > thresh && + medianwin[middle] > medianwin[middle-1] && + medianwin[middle] > medianwin[middle+1] && + softPeakAmnesty == 0) { + + size_t maxindex = middle; + float maxval = medianwin[middle]; + + for (size_t j = middle+1; j < mediansize; ++j) { + if (medianwin[j] > maxval) { + maxval = medianwin[j]; + maxindex = j; + } else if (medianwin[j] < medianwin[middle]) { + break; + } + } + + size_t peak = i + maxindex - middle; + +// std::cerr << "i = " << i << ", maxindex = " << maxindex << ", middle = " << middle << ", so peak at " << peak << std::endl; + + if (softPeakCandidates.empty() || lastSoftPeak != peak) { + + if (m_debugLevel > 1) { + std::cerr << "soft peak at " << peak << " (" + << peak * m_increment << "): " + << medianwin[middle] << " > " + << thresh << " and " + << medianwin[middle] + << " > " << medianwin[middle-1] << " and " + << medianwin[middle] + << " > " << medianwin[middle+1] + << std::endl; + } + + if (peak >= df.size()) { + if (m_debugLevel > 2) { + std::cerr << "peak is beyond end" << std::endl; + } + } else { + softPeakCandidates.insert(peak); + lastSoftPeak = peak; + } + } + + softPeakAmnesty = minspacing + maxindex - middle; + if (m_debugLevel > 2) { + std::cerr << "amnesty = " << softPeakAmnesty << std::endl; + } + + } else if (softPeakAmnesty > 0) --softPeakAmnesty; + + if (mediansize >= medianmaxsize) { + medianwin.pop_front(); + } + if (nextDf < df.size()) { + medianwin.push_back(df[nextDf]); + } else { + medianwin.push_back(0); + } + } + + std::vector<Peak> peaks; + + while (!hardPeakCandidates.empty() || !softPeakCandidates.empty()) { + + bool haveHardPeak = !hardPeakCandidates.empty(); + bool haveSoftPeak = !softPeakCandidates.empty(); + + size_t hardPeak = (haveHardPeak ? *hardPeakCandidates.begin() : 0); + size_t softPeak = (haveSoftPeak ? *softPeakCandidates.begin() : 0); + + Peak peak; + peak.hard = false; + peak.chunk = softPeak; + + bool ignore = false; + + if (haveHardPeak && + (!haveSoftPeak || hardPeak <= softPeak)) { + + if (m_debugLevel > 2) { + std::cerr << "Hard peak: " << hardPeak << std::endl; + } + + peak.hard = true; + peak.chunk = hardPeak; + hardPeakCandidates.erase(hardPeakCandidates.begin()); + + } else { + if (m_debugLevel > 2) { + std::cerr << "Soft peak: " << softPeak << std::endl; + } + if (!peaks.empty() && + peaks[peaks.size()-1].hard && + peaks[peaks.size()-1].chunk + 3 >= softPeak) { + if (m_debugLevel > 2) { + std::cerr << "(ignoring, as we just had a hard peak)" + << std::endl; + } + ignore = true; + } + } + + if (haveSoftPeak && peak.chunk == softPeak) { + softPeakCandidates.erase(softPeakCandidates.begin()); + } + + if (!ignore) { + peaks.push_back(peak); + } + } + + return peaks; +} + +std::vector<float> +StretchCalculator::smoothDF(const std::vector<float> &df) +{ + std::vector<float> smoothedDF; + + for (size_t i = 0; i < df.size(); ++i) { + // three-value moving mean window for simple smoothing + float total = 0.f, count = 0; + if (i > 0) { total += df[i-1]; ++count; } + total += df[i]; ++count; + if (i+1 < df.size()) { total += df[i+1]; ++count; } + float mean = total / count; + smoothedDF.push_back(mean); + } + + return smoothedDF; +} + +std::vector<int> +StretchCalculator::distributeRegion(const std::vector<float> &dfIn, + size_t duration, float ratio, bool phaseReset) +{ + std::vector<float> df(dfIn); + std::vector<int> increments; + + // The peak for the stretch detection function may appear after + // the peak that we're using to calculate the start of the region. + // We don't want that. If we find a peak in the first half of + // the region, we should set all the values up to that point to + // the same value as the peak. + + // (This might not be subtle enough, especially if the region is + // long -- we want a bound that corresponds to acoustic perception + // of the audible bounce.) + + for (size_t i = 1; i < df.size()/2; ++i) { + if (df[i] < df[i-1]) { + if (m_debugLevel > 1) { + std::cerr << "stretch peak offset: " << i-1 << " (peak " << df[i-1] << ")" << std::endl; + } + for (size_t j = 0; j < i-1; ++j) { + df[j] = df[i-1]; + } + break; + } + } + + float maxDf = 0; + + for (size_t i = 0; i < df.size(); ++i) { + if (i == 0 || df[i] > maxDf) maxDf = df[i]; + } + + // We want to try to ensure the last 100ms or so (if possible) are + // tending back towards the maximum df, so that the stretchiness + // reduces at the end of the stretched region. + + int reducedRegion = lrint((0.1 * m_sampleRate) / m_increment); + if (reducedRegion > int(df.size()/5)) reducedRegion = df.size()/5; + + for (int i = 0; i < reducedRegion; ++i) { + size_t index = df.size() - reducedRegion + i; + df[index] = df[index] + ((maxDf - df[index]) * i) / reducedRegion; + } + + long toAllot = long(duration) - long(m_increment * df.size()); + + if (m_debugLevel > 1) { + std::cerr << "region of " << df.size() << " chunks, output duration " << duration << ", toAllot " << toAllot << std::endl; + } + + size_t totalIncrement = 0; + + // We place limits on the amount of displacement per chunk. if + // ratio < 0, no increment should be larger than increment*ratio + // or smaller than increment*ratio/2; if ratio > 0, none should be + // smaller than increment*ratio or larger than increment*ratio*2. + // We need to enforce this in the assignment of displacements to + // allotments, not by trying to respond if something turns out + // wrong. + + // Note that the ratio is only provided to this function for the + // purposes of establishing this bound to the displacement. + + // so if + // maxDisplacement / totalDisplacement > increment * ratio*2 - increment + // (for ratio > 1) + // or + // maxDisplacement / totalDisplacement < increment * ratio/2 + // (for ratio < 1) + + // then we need to adjust and accommodate + + bool acceptableSquashRange = false; + + double totalDisplacement = 0; + double maxDisplacement = 0; // min displacement will be 0 by definition + + maxDf = 0; + float adj = 0; + + while (!acceptableSquashRange) { + + acceptableSquashRange = true; + calculateDisplacements(df, maxDf, totalDisplacement, maxDisplacement, + adj); + + if (m_debugLevel > 1) { + std::cerr << "totalDisplacement " << totalDisplacement << ", max " << maxDisplacement << " (maxDf " << maxDf << ", df count " << df.size() << ")" << std::endl; + } + + if (totalDisplacement == 0) { +// Not usually a problem, in fact +// std::cerr << "WARNING: totalDisplacement == 0 (duration " << duration << ", " << df.size() << " values in df)" << std::endl; + if (!df.empty() && adj == 0) { + acceptableSquashRange = false; + adj = 1; + } + continue; + } + + int extremeIncrement = m_increment + lrint((toAllot * maxDisplacement) / totalDisplacement); + if (ratio < 1.0) { + if (extremeIncrement > lrint(ceil(m_increment * ratio))) { + std::cerr << "ERROR: extreme increment " << extremeIncrement << " > " << m_increment * ratio << " (this should not happen)" << std::endl; + } else if (extremeIncrement < (m_increment * ratio) / 2) { + if (m_debugLevel > 0) { + std::cerr << "WARNING: extreme increment " << extremeIncrement << " < " << (m_increment * ratio) / 2 << std::endl; + } + acceptableSquashRange = false; + } + } else { + if (extremeIncrement > m_increment * ratio * 2) { + if (m_debugLevel > 0) { + std::cerr << "WARNING: extreme increment " << extremeIncrement << " > " << m_increment * ratio * 2 << std::endl; + } + acceptableSquashRange = false; + } else if (extremeIncrement < lrint(floor(m_increment * ratio))) { + std::cerr << "ERROR: extreme increment " << extremeIncrement << " < " << m_increment * ratio << " (I thought this couldn't happen?)" << std::endl; + } + } + + if (!acceptableSquashRange) { + // Need to make maxDisplacement smaller as a proportion of + // the total displacement, yet ensure that the + // displacements still sum to the total. + adj += maxDf/10; + } + } + + for (size_t i = 0; i < df.size(); ++i) { + + double displacement = maxDf - df[i]; + if (displacement < 0) displacement -= adj; + else displacement += adj; + + if (i == 0 && phaseReset) { + if (df.size() == 1) { + increments.push_back(duration); + totalIncrement += duration; + } else { + increments.push_back(m_increment); + totalIncrement += m_increment; + } + totalDisplacement -= displacement; + continue; + } + + double theoreticalAllotment = 0; + + if (totalDisplacement != 0) { + theoreticalAllotment = (toAllot * displacement) / totalDisplacement; + } + int allotment = lrint(theoreticalAllotment); + if (i + 1 == df.size()) allotment = toAllot; + + int increment = m_increment + allotment; + + if (increment <= 0) { + // this is a serious problem, the allocation is quite + // wrong if it allows increment to diverge so far from the + // input increment + std::cerr << "*** WARNING: increment " << increment << " <= 0, rounding to zero" << std::endl; + increment = 0; + allotment = increment - m_increment; + } + + increments.push_back(increment); + totalIncrement += increment; + + toAllot -= allotment; + totalDisplacement -= displacement; + + if (m_debugLevel > 2) { + std::cerr << "df " << df[i] << ", smoothed " << df[i] << ", disp " << displacement << ", allot " << theoreticalAllotment << ", incr " << increment << ", remain " << toAllot << std::endl; + } + } + + if (m_debugLevel > 2) { + std::cerr << "total increment: " << totalIncrement << ", left over: " << toAllot << " to allot, displacement " << totalDisplacement << std::endl; + } + + if (totalIncrement != duration) { + std::cerr << "*** WARNING: calculated output duration " << totalIncrement << " != expected " << duration << std::endl; + } + + return increments; +} + +void +StretchCalculator::calculateDisplacements(const std::vector<float> &df, + float &maxDf, + double &totalDisplacement, + double &maxDisplacement, + float adj) const +{ + totalDisplacement = maxDisplacement = 0; + + maxDf = 0; + + for (size_t i = 0; i < df.size(); ++i) { + if (i == 0 || df[i] > maxDf) maxDf = df[i]; + } + + for (size_t i = 0; i < df.size(); ++i) { + double displacement = maxDf - df[i]; + if (displacement < 0) displacement -= adj; + else displacement += adj; + totalDisplacement += displacement; + if (i == 0 || displacement > maxDisplacement) { + maxDisplacement = displacement; + } + } +} + +} + diff --git a/libs/rubberband/1.0/src/StretchCalculator.h b/libs/rubberband/1.0/src/StretchCalculator.h new file mode 100644 index 0000000000..f6c3544b2d --- /dev/null +++ b/libs/rubberband/1.0/src/StretchCalculator.h @@ -0,0 +1,95 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_STRETCH_CALCULATOR_H_ +#define _RUBBERBAND_STRETCH_CALCULATOR_H_ + +#include <sys/types.h> + +#include <vector> + +namespace RubberBand +{ + +class StretchCalculator +{ +public: + StretchCalculator(size_t sampleRate, size_t inputIncrement, bool useHardPeaks); + virtual ~StretchCalculator(); + + /** + * Calculate phase increments for a region of audio, given the + * overall target stretch ratio, input duration in audio samples, + * and the audio curves to use for identifying phase lock points + * (lockAudioCurve) and for allocating stretches to relatively + * less prominent points (stretchAudioCurve). + */ + virtual std::vector<int> calculate(double ratio, size_t inputDuration, + const std::vector<float> &lockAudioCurve, + const std::vector<float> &stretchAudioCurve); + + /** + * Calculate the phase increment for a single audio block, given + * the overall target stretch ratio and the block's value on the + * phase-lock audio curve. State is retained between calls in the + * StretchCalculator object; call reset() to reset it. This uses + * a less sophisticated method than the offline calculate(). + */ + virtual int calculateSingle(double ratio, size_t inputDurationSoFar, + float curveValue); + + void setUseHardPeaks(bool use) { m_useHardPeaks = use; } + + void reset(); + + void setDebugLevel(int level) { m_debugLevel = level; } + + struct Peak { + size_t chunk; + bool hard; + }; + std::vector<Peak> getLastCalculatedPeaks() const { return m_lastPeaks; } + + std::vector<float> smoothDF(const std::vector<float> &df); + +protected: + std::vector<Peak> findPeaks(const std::vector<float> &audioCurve); + + std::vector<int> distributeRegion(const std::vector<float> ®ionCurve, + size_t outputDuration, float ratio, + bool phaseReset); + + void calculateDisplacements(const std::vector<float> &df, + float &maxDf, + double &totalDisplacement, + double &maxDisplacement, + float adj) const; + + size_t m_sampleRate; + size_t m_blockSize; + size_t m_increment; + float m_prevDf; + double m_divergence; + float m_recovery; + float m_prevRatio; + int m_transientAmnesty; // only in RT mode; handled differently offline + int m_debugLevel; + bool m_useHardPeaks; + + std::vector<Peak> m_lastPeaks; +}; + +} + +#endif diff --git a/libs/rubberband/1.0/src/StretcherChannelData.cpp b/libs/rubberband/1.0/src/StretcherChannelData.cpp new file mode 100644 index 0000000000..ecbb9a6b88 --- /dev/null +++ b/libs/rubberband/1.0/src/StretcherChannelData.cpp @@ -0,0 +1,271 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +#include "StretcherChannelData.h" + +#include "Resampler.h" + +namespace RubberBand +{ + +RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize, + size_t outbufSize) +{ + std::set<size_t> s; + construct(s, windowSize, outbufSize); +} + +RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &windowSizes, + size_t initialWindowSize, + size_t outbufSize) +{ + construct(windowSizes, initialWindowSize, outbufSize); +} + +void +RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &windowSizes, + size_t initialWindowSize, + size_t outbufSize) +{ + size_t maxSize = initialWindowSize; + + if (!windowSizes.empty()) { + // std::set is ordered by value + std::set<size_t>::const_iterator i = windowSizes.end(); + maxSize = *--i; + } + if (windowSizes.find(initialWindowSize) == windowSizes.end()) { + if (initialWindowSize > maxSize) maxSize = initialWindowSize; + } + + size_t realSize = maxSize/2 + 1; // size of the real "half" of freq data + +// std::cerr << "ChannelData::construct([" << windowSizes.size() << "], " << maxSize << ", " << outbufSize << ")" << std::endl; + + if (outbufSize < maxSize) outbufSize = maxSize; + + inbuf = new RingBuffer<float>(maxSize); + outbuf = new RingBuffer<float>(outbufSize); + + mag = new double[realSize]; + phase = new double[realSize]; + prevPhase = new double[realSize]; + unwrappedPhase = new double[realSize]; + freqPeak = new size_t[realSize]; + + accumulator = new float[maxSize]; + windowAccumulator = new float[maxSize]; + + fltbuf = new float[maxSize]; + + for (std::set<size_t>::const_iterator i = windowSizes.begin(); + i != windowSizes.end(); ++i) { + ffts[*i] = new FFT(*i); + ffts[*i]->initDouble(); + } + if (windowSizes.find(initialWindowSize) == windowSizes.end()) { + ffts[initialWindowSize] = new FFT(initialWindowSize); + ffts[initialWindowSize]->initDouble(); + } + fft = ffts[initialWindowSize]; + + dblbuf = fft->getDoubleTimeBuffer(); + + resampler = 0; + resamplebuf = 0; + resamplebufSize = 0; + + reset(); + + for (size_t i = 0; i < realSize; ++i) { + mag[i] = 0.0; + phase[i] = 0.0; + prevPhase[i] = 0.0; + unwrappedPhase[i] = 0.0; + freqPeak[i] = 0; + } + + for (size_t i = 0; i < initialWindowSize; ++i) { + dblbuf[i] = 0.0; + } + + for (size_t i = 0; i < maxSize; ++i) { + accumulator[i] = 0.f; + windowAccumulator[i] = 0.f; + fltbuf[i] = 0.0; + } +} + +void +RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize) +{ + size_t oldSize = inbuf->getSize(); + size_t realSize = windowSize/2 + 1; + +// std::cerr << "ChannelData::setWindowSize(" << windowSize << ") [from " << oldSize << "]" << std::endl; + + if (oldSize >= windowSize) { + + // no need to reallocate buffers, just reselect fft + + //!!! we can't actually do this without locking against the + //process thread, can we? we need to zero the mag/phase + //buffers without interference + + if (ffts.find(windowSize) == ffts.end()) { + //!!! this also requires a lock, but it shouldn't occur in + //RT mode with proper initialisation + ffts[windowSize] = new FFT(windowSize); + ffts[windowSize]->initDouble(); + } + + fft = ffts[windowSize]; + + dblbuf = fft->getDoubleTimeBuffer(); + + for (size_t i = 0; i < windowSize; ++i) { + dblbuf[i] = 0.0; + } + + for (size_t i = 0; i < realSize; ++i) { + mag[i] = 0.0; + phase[i] = 0.0; + prevPhase[i] = 0.0; + unwrappedPhase[i] = 0.0; + freqPeak[i] = 0; + } + + return; + } + + //!!! at this point we need a lock in case a different client + //thread is calling process() -- we need this lock even if we + //aren't running in threaded mode ourselves -- if we're in RT + //mode, then the process call should trylock and fail if the lock + //is unavailable (since this should never normally be the case in + //general use in RT mode) + + RingBuffer<float> *newbuf = inbuf->resized(windowSize); + delete inbuf; + inbuf = newbuf; + + // We don't want to preserve data in these arrays + + delete[] mag; + delete[] phase; + delete[] prevPhase; + delete[] unwrappedPhase; + delete[] freqPeak; + + mag = new double[realSize]; + phase = new double[realSize]; + prevPhase = new double[realSize]; + unwrappedPhase = new double[realSize]; + freqPeak = new size_t[realSize]; + + delete[] fltbuf; + fltbuf = new float[windowSize]; + + // But we do want to preserve data in these + + float *newAcc = new float[windowSize]; + for (size_t i = 0; i < oldSize; ++i) newAcc[i] = accumulator[i]; + delete[] accumulator; + accumulator = newAcc; + + newAcc = new float[windowSize]; + for (size_t i = 0; i < oldSize; ++i) newAcc[i] = windowAccumulator[i]; + delete[] windowAccumulator; + windowAccumulator = newAcc; + + //!!! and resampler? + + for (size_t i = 0; i < realSize; ++i) { + mag[i] = 0.0; + phase[i] = 0.0; + prevPhase[i] = 0.0; + unwrappedPhase[i] = 0.0; + freqPeak[i] = 0; + } + + for (size_t i = 0; i < windowSize; ++i) { + fltbuf[i] = 0.0; + } + + for (size_t i = oldSize; i < windowSize; ++i) { + accumulator[i] = 0.f; + windowAccumulator[i] = 0.f; + } + + if (ffts.find(windowSize) == ffts.end()) { + ffts[windowSize] = new FFT(windowSize); + ffts[windowSize]->initDouble(); + } + + fft = ffts[windowSize]; + + dblbuf = fft->getDoubleTimeBuffer(); + + for (size_t i = 0; i < windowSize; ++i) { + dblbuf[i] = 0.0; + } +} + +void +RubberBandStretcher::Impl::ChannelData::setOutbufSize(size_t outbufSize) +{ + size_t oldSize = outbuf->getSize(); + +// std::cerr << "ChannelData::setOutbufSize(" << outbufSize << ") [from " << oldSize << "]" << std::endl; + + if (oldSize < outbufSize) { + + //!!! at this point we need a lock in case a different client + //thread is calling process() + + RingBuffer<float> *newbuf = outbuf->resized(outbufSize); + delete outbuf; + outbuf = newbuf; + } +} + +RubberBandStretcher::Impl::ChannelData::~ChannelData() +{ + delete resampler; + delete[] resamplebuf; + + delete inbuf; + delete outbuf; + delete[] mag; + delete[] phase; + delete[] prevPhase; + delete[] unwrappedPhase; + delete[] freqPeak; + delete[] accumulator; + delete[] windowAccumulator; + delete[] fltbuf; + + for (std::map<size_t, FFT *>::iterator i = ffts.begin(); + i != ffts.end(); ++i) { + delete i->second; + } +} + +void +RubberBandStretcher::Impl::ChannelData::reset() +{ + inbuf->reset(); + outbuf->reset(); + + if (resampler) resampler->reset(); + + accumulatorFill = 0; + prevIncrement = 0; + chunkCount = 0; + inCount = 0; + inputSize = -1; + outCount = 0; + draining = false; + outputComplete = false; +} + +} diff --git a/libs/rubberband/1.0/src/StretcherChannelData.h b/libs/rubberband/1.0/src/StretcherChannelData.h new file mode 100644 index 0000000000..ff110d14b6 --- /dev/null +++ b/libs/rubberband/1.0/src/StretcherChannelData.h @@ -0,0 +1,121 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_STRETCHERCHANNELDATA_H_ +#define _RUBBERBAND_STRETCHERCHANNELDATA_H_ + +#include "StretcherImpl.h" + +#include <set> + +namespace RubberBand +{ + +class Resampler; + +class RubberBandStretcher::Impl::ChannelData +{ +public: + /** + * Construct a ChannelData structure. + * + * The window size passed in here is the size for the FFT + * calculation, and most of the buffer sizes also depend on + * it. In practice it is always a power of two and except for + * very extreme stretches is always either 1024, 2048 or 4096. + * + * The outbuf size depends on other factors as well, including + * the pitch scale factor and any maximum processing block + * size specified by the user of the code. + */ + ChannelData(size_t windowSize, size_t outbufSize); + + /** + * Construct a ChannelData structure that can process at + * different FFT sizes without requiring reallocation when the + * size changes. The size can subsequently be changed with a + * call to setWindowSize. Reallocation will only be necessary + * if setWindowSize is called with a value not equal to one of + * those passed in to the constructor. + * + * The outbufSize should be the maximum possible outbufSize to + * avoid reallocation, which will happen if setOutbufSize is + * called subsequently. + */ + ChannelData(const std::set<size_t> &windowSizes, + size_t initialWindowSize, size_t outbufSize); + ~ChannelData(); + + /** + * Reset buffers + */ + void reset(); + + /** + * Set the FFT and buffer sizes from the given processing + * window size. If this ChannelData was constructed with a set + * of window sizes and the given window size here was among + * them, no reallocation will be required. + */ + void setWindowSize(size_t windowSize); + + /** + * Set the outbufSize for the channel data. Reallocation will + * occur. + */ + void setOutbufSize(size_t outbufSize); + + RingBuffer<float> *inbuf; + RingBuffer<float> *outbuf; + + double *mag; + double *phase; + + double *prevPhase; + double *unwrappedPhase; + + size_t *freqPeak; + + float *accumulator; + size_t accumulatorFill; + float *windowAccumulator; + + float *fltbuf; + double *dblbuf; // owned by FFT object, only used for time domain FFT i/o + + size_t prevIncrement; // only used in RT mode + + size_t chunkCount; + size_t inCount; + long inputSize; // set only after known (when data ended); -1 previously + size_t outCount; + + bool draining; + bool outputComplete; + + FFT *fft; + std::map<size_t, FFT *> ffts; + + Resampler *resampler; + float *resamplebuf; + size_t resamplebufSize; + +private: + void construct(const std::set<size_t> &windowSizes, + size_t initialWindowSize, size_t outbufSize); +}; + +} + +#endif diff --git a/libs/rubberband/1.0/src/StretcherImpl.cpp b/libs/rubberband/1.0/src/StretcherImpl.cpp new file mode 100644 index 0000000000..30bc529bc8 --- /dev/null +++ b/libs/rubberband/1.0/src/StretcherImpl.cpp @@ -0,0 +1,1023 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "StretcherImpl.h" +#include "PercussiveAudioCurve.h" +#include "HighFrequencyAudioCurve.h" +#include "SpectralDifferenceAudioCurve.h" +#include "ConstantAudioCurve.h" +#include "StretchCalculator.h" +#include "StretcherChannelData.h" +#include "Resampler.h" + +#include <cassert> +#include <cmath> +#include <set> +#include <map> + +using std::cerr; +using std::endl; +using std::vector; +using std::map; +using std::set; +using std::max; +using std::min; + +namespace RubberBand { + +const size_t +RubberBandStretcher::Impl::m_defaultIncrement = 256; + +const size_t +RubberBandStretcher::Impl::m_defaultWindowSize = 2048; + +int +RubberBandStretcher::Impl::m_defaultDebugLevel = 0; + + +RubberBandStretcher::Impl::Impl(RubberBandStretcher *stretcher, + size_t sampleRate, + size_t channels, + Options options, + double initialTimeRatio, + double initialPitchScale) : + m_stretcher(stretcher), + m_channels(channels), + m_timeRatio(initialTimeRatio), + m_pitchScale(initialPitchScale), + m_windowSize(m_defaultWindowSize), + m_increment(m_defaultIncrement), + m_outbufSize(m_defaultWindowSize * 2), + m_maxProcessSize(m_defaultWindowSize), + m_expectedInputDuration(0), + m_threaded(false), + m_realtime(false), + m_options(options), + m_debugLevel(m_defaultDebugLevel), + m_mode(JustCreated), + m_window(0), + m_studyFFT(0), + m_spaceAvailable("space"), + m_inputDuration(0), + m_lastProcessOutputIncrements(16), + m_lastProcessPhaseResetDf(16), + m_phaseResetAudioCurve(0), + m_stretchAudioCurve(0), + m_stretchCalculator(0), + m_freq0(600), + m_freq1(1200), + m_freq2(12000), + m_baseWindowSize(m_defaultWindowSize) +{ + if (m_debugLevel > 0) { + cerr << "RubberBandStretcher::Impl::Impl: rate = " << m_stretcher->m_sampleRate << ", options = " << options << endl; + } + + // Window size will vary according to the audio sample rate, but + // we don't let it drop below the 48k default + m_rateMultiple = float(m_stretcher->m_sampleRate) / 48000.f; + if (m_rateMultiple < 1.f) m_rateMultiple = 1.f; + m_baseWindowSize = roundUp(int(m_defaultWindowSize * m_rateMultiple)); + + if ((options & OptionWindowShort) || (options & OptionWindowLong)) { + if ((options & OptionWindowShort) && (options & OptionWindowLong)) { + cerr << "RubberBandStretcher::Impl::Impl: Cannot specify OptionWindowLong and OptionWindowShort together; falling back to OptionWindowStandard" << endl; + } else if (options & OptionWindowShort) { + m_baseWindowSize = m_baseWindowSize / 2; + if (m_debugLevel > 0) { + cerr << "setting baseWindowSize to " << m_baseWindowSize << endl; + } + } else if (options & OptionWindowLong) { + m_baseWindowSize = m_baseWindowSize * 2; + if (m_debugLevel > 0) { + cerr << "setting baseWindowSize to " << m_baseWindowSize << endl; + } + } + m_windowSize = m_baseWindowSize; + m_outbufSize = m_baseWindowSize * 2; + m_maxProcessSize = m_baseWindowSize; + } + + if (m_options & OptionProcessRealTime) { + + m_realtime = true; + + if (!(m_options & OptionStretchPrecise)) { + m_options |= OptionStretchPrecise; + } + } + + if (m_channels > 1) { + + m_threaded = true; + + if (m_realtime) { + m_threaded = false; + } else if (m_options & OptionThreadingNever) { + m_threaded = false; + } else if (!(m_options & OptionThreadingAlways) && + !system_is_multiprocessor()) { + m_threaded = false; + } + + if (m_threaded && m_debugLevel > 0) { + cerr << "Going multithreaded..." << endl; + } + } + + configure(); +} + +RubberBandStretcher::Impl::~Impl() +{ + if (m_threaded) { + MutexLocker locker(&m_threadSetMutex); + for (set<ProcessThread *>::iterator i = m_threadSet.begin(); + i != m_threadSet.end(); ++i) { + if (m_debugLevel > 0) { + cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl; + } + (*i)->abandon(); + (*i)->wait(); + delete *i; + } + } + + for (size_t c = 0; c < m_channels; ++c) { + delete m_channelData[c]; + } + + delete m_phaseResetAudioCurve; + delete m_stretchAudioCurve; + delete m_stretchCalculator; + delete m_studyFFT; + + for (map<size_t, Window<float> *>::iterator i = m_windows.begin(); + i != m_windows.end(); ++i) { + delete i->second; + } +} + +void +RubberBandStretcher::Impl::reset() +{ + if (m_threaded) { + m_threadSetMutex.lock(); + for (set<ProcessThread *>::iterator i = m_threadSet.begin(); + i != m_threadSet.end(); ++i) { + if (m_debugLevel > 0) { + cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl; + } + (*i)->abandon(); + (*i)->wait(); + delete *i; + } + m_threadSet.clear(); + } + + for (size_t c = 0; c < m_channels; ++c) { + m_channelData[c]->reset(); + } + + m_mode = JustCreated; + if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset(); + if (m_stretchAudioCurve) m_stretchAudioCurve->reset(); + m_inputDuration = 0; + + if (m_threaded) m_threadSetMutex.unlock(); + + reconfigure(); +} + +void +RubberBandStretcher::Impl::setTimeRatio(double ratio) +{ + if (!m_realtime) { + if (m_mode == Studying || m_mode == Processing) { + cerr << "RubberBandStretcher::Impl::setTimeRatio: Cannot set ratio while studying or processing in non-RT mode" << endl; + return; + } + } + + if (ratio == m_timeRatio) return; + m_timeRatio = ratio; + + reconfigure(); +} + +void +RubberBandStretcher::Impl::setPitchScale(double fs) +{ + if (!m_realtime) { + if (m_mode == Studying || m_mode == Processing) { + cerr << "RubberBandStretcher::Impl::setPitchScale: Cannot set ratio while studying or processing in non-RT mode" << endl; + return; + } + } + + if (fs == m_pitchScale) return; + m_pitchScale = fs; + + reconfigure(); +} + +double +RubberBandStretcher::Impl::getTimeRatio() const +{ + return m_timeRatio; +} + +double +RubberBandStretcher::Impl::getPitchScale() const +{ + return m_pitchScale; +} + +void +RubberBandStretcher::Impl::setExpectedInputDuration(size_t samples) +{ + if (samples == m_expectedInputDuration) return; + m_expectedInputDuration = samples; + + reconfigure(); +} + +void +RubberBandStretcher::Impl::setMaxProcessSize(size_t samples) +{ + if (samples <= m_maxProcessSize) return; + m_maxProcessSize = samples; + + reconfigure(); +} + +float +RubberBandStretcher::Impl::getFrequencyCutoff(int n) const +{ + switch (n) { + case 0: return m_freq0; + case 1: return m_freq1; + case 2: return m_freq2; + } + return 0.f; +} + +void +RubberBandStretcher::Impl::setFrequencyCutoff(int n, float f) +{ + switch (n) { + case 0: m_freq0 = f; break; + case 1: m_freq1 = f; break; + case 2: m_freq2 = f; break; + } +} + +double +RubberBandStretcher::Impl::getEffectiveRatio() const +{ + // Returns the ratio that the internal time stretcher needs to + // achieve, not the resulting duration ratio of the output (which + // is simply m_timeRatio). + + // A frequency shift is achieved using an additional time shift, + // followed by resampling back to the original time shift to + // change the pitch. Note that the resulting frequency change is + // fixed, as it is effected by the resampler -- in contrast to + // time shifting, which is variable aiming to place the majority + // of the stretch or squash in low-interest regions of audio. + + return m_timeRatio * m_pitchScale; +} + +size_t +RubberBandStretcher::Impl::roundUp(size_t value) +{ + if (!(value & (value - 1))) return value; + int bits = 0; + while (value) { ++bits; value >>= 1; } + value = 1 << bits; + return value; +} + +void +RubberBandStretcher::Impl::calculateSizes() +{ + size_t inputIncrement = m_defaultIncrement; + size_t windowSize = m_baseWindowSize; + size_t outputIncrement; + + double r = getEffectiveRatio(); + + if (m_realtime) { + + // use a fixed input increment + + inputIncrement = roundUp(int(m_defaultIncrement * m_rateMultiple)); + + if (r < 1) { + outputIncrement = int(floor(inputIncrement * r)); + if (outputIncrement < 1) { + outputIncrement = 1; + inputIncrement = roundUp(lrint(ceil(outputIncrement / r))); + windowSize = inputIncrement * 4; + } + } else { + outputIncrement = int(ceil(inputIncrement * r)); + while (outputIncrement > 1024 && inputIncrement > 1) { + inputIncrement /= 2; + outputIncrement = lrint(ceil(inputIncrement * r)); + } + windowSize = std::max(windowSize, roundUp(outputIncrement * 6)); + if (r > 5) while (windowSize < 8192) windowSize *= 2; + } + + } else { + + // use a variable increment + + if (r < 1) { + inputIncrement = windowSize / 4; + while (inputIncrement >= 512) inputIncrement /= 2; + outputIncrement = int(floor(inputIncrement * r)); + if (outputIncrement < 1) { + outputIncrement = 1; + inputIncrement = roundUp(lrint(ceil(outputIncrement / r))); + windowSize = inputIncrement * 4; + } + } else { + outputIncrement = windowSize / 6; + inputIncrement = int(outputIncrement / r); + while (outputIncrement > 1024 && inputIncrement > 1) { + outputIncrement /= 2; + inputIncrement = int(outputIncrement / r); + } + windowSize = std::max(windowSize, roundUp(outputIncrement * 6)); + if (r > 5) while (windowSize < 8192) windowSize *= 2; + } + } + + if (m_expectedInputDuration > 0) { + while (inputIncrement * 4 > m_expectedInputDuration && + inputIncrement > 1) { + inputIncrement /= 2; + } + } + + // windowSize can be almost anything, but it can't be greater than + // 4 * m_baseWindowSize unless ratio is less than 1/1024. + + m_windowSize = windowSize; + m_increment = inputIncrement; + + // When squashing, the greatest theoretically possible output + // increment is the input increment. When stretching adaptively + // the sky's the limit in principle, but we expect + // StretchCalculator to restrict itself to using no more than + // twice the basic output increment (i.e. input increment times + // ratio) for any chunk. + + if (m_debugLevel > 0) { + cerr << "configure: effective ratio = " << getEffectiveRatio() << endl; + cerr << "configure: window size = " << m_windowSize << ", increment = " << m_increment << " (approx output increment = " << int(lrint(m_increment * getEffectiveRatio())) << ")" << endl; + } + + if (m_windowSize > m_maxProcessSize) { + m_maxProcessSize = m_windowSize; + } + + m_outbufSize = + size_t + (ceil(max + (m_maxProcessSize / m_pitchScale, + m_windowSize * 2 * (m_timeRatio > 1.f ? m_timeRatio : 1.f)))); + + if (m_realtime) { + // This headroom is so as to try to avoid reallocation when + // the pitch scale changes + m_outbufSize = m_outbufSize * 16; + } else { + if (m_threaded) { + // This headroom is to permit the processing threads to + // run ahead of the buffer output drainage; the exact + // amount of headroom is a question of tuning rather than + // results + m_outbufSize = m_outbufSize * 16; + } + } + + if (m_debugLevel > 0) { + cerr << "configure: outbuf size = " << m_outbufSize << endl; + } +} + +void +RubberBandStretcher::Impl::configure() +{ +// std::cerr << "configure[" << this << "]: realtime = " << m_realtime << ", pitch scale = " +// << m_pitchScale << ", channels = " << m_channels << std::endl; + + size_t prevWindowSize = m_windowSize; + size_t prevOutbufSize = m_outbufSize; + if (m_windows.empty()) { + prevWindowSize = 0; + prevOutbufSize = 0; + } + + calculateSizes(); + + bool windowSizeChanged = (prevWindowSize != m_windowSize); + bool outbufSizeChanged = (prevOutbufSize != m_outbufSize); + + // This function may be called at any time in non-RT mode, after a + // parameter has changed. It shouldn't be legal to call it after + // processing has already begun. + + // This function is only called once (on construction) in RT + // mode. After that reconfigure() does the work in a hopefully + // RT-safe way. + + set<size_t> windowSizes; + if (m_realtime) { + windowSizes.insert(m_baseWindowSize); + windowSizes.insert(m_baseWindowSize * 2); + windowSizes.insert(m_baseWindowSize * 4); + } + windowSizes.insert(m_windowSize); + + if (windowSizeChanged) { + + for (set<size_t>::const_iterator i = windowSizes.begin(); + i != windowSizes.end(); ++i) { + if (m_windows.find(*i) == m_windows.end()) { + m_windows[*i] = new Window<float>(HanningWindow, *i); + } + } + m_window = m_windows[m_windowSize]; + + if (m_debugLevel > 0) { + cerr << "Window area: " << m_window->getArea() << "; synthesis window area: " << m_window->getArea() << endl; + } + } + + if (windowSizeChanged || outbufSizeChanged) { + + for (size_t c = 0; c < m_channelData.size(); ++c) { + delete m_channelData[c]; + } + m_channelData.clear(); + + for (size_t c = 0; c < m_channels; ++c) { + m_channelData.push_back + (new ChannelData(windowSizes, m_windowSize, m_outbufSize)); + } + } + + if (!m_realtime && windowSizeChanged) { + delete m_studyFFT; + m_studyFFT = new FFT(m_windowSize); + m_studyFFT->initFloat(); + } + + if (m_pitchScale != 1.0 || m_realtime) { + + for (size_t c = 0; c < m_channels; ++c) { + + if (m_channelData[c]->resampler) continue; + + m_channelData[c]->resampler = + new Resampler(Resampler::FastestTolerable, 1, 4096 * 16); + + // rbs is the amount of buffer space we think we'll need + // for resampling; but allocate a sensible amount in case + // the pitch scale changes during use + size_t rbs = + lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale)); + if (rbs < m_increment * 16) rbs = m_increment * 16; + m_channelData[c]->resamplebufSize = rbs; + m_channelData[c]->resamplebuf = new float[rbs]; + } + } + + delete m_phaseResetAudioCurve; + m_phaseResetAudioCurve = new PercussiveAudioCurve(m_stretcher->m_sampleRate, + m_windowSize); + + // stretchAudioCurve unused in RT mode; phaseResetAudioCurve and + // stretchCalculator however are used in all modes + + if (!m_realtime) { + delete m_stretchAudioCurve; + if (!(m_options & OptionStretchPrecise)) { + m_stretchAudioCurve = new SpectralDifferenceAudioCurve + (m_stretcher->m_sampleRate, m_windowSize); + } else { + m_stretchAudioCurve = new ConstantAudioCurve + (m_stretcher->m_sampleRate, m_windowSize); + } + } + + delete m_stretchCalculator; + m_stretchCalculator = new StretchCalculator + (m_stretcher->m_sampleRate, m_increment, + !(m_options & OptionTransientsSmooth)); + + m_stretchCalculator->setDebugLevel(m_debugLevel); + m_inputDuration = 0; + + // Prepare the inbufs with half a chunk of emptiness. The centre + // point of the first processing chunk for the onset detector + // should be the first sample of the audio, and we continue until + // we can no longer centre a chunk within the input audio. The + // number of onset detector chunks will be the number of audio + // samples input, divided by the input increment, plus one. + + // In real-time mode, we don't do this prefill -- it's better to + // start with a swoosh than introduce more latency, and we don't + // want gaps when the ratio changes. + + if (!m_realtime) { + for (size_t c = 0; c < m_channels; ++c) { + m_channelData[c]->reset(); + m_channelData[c]->inbuf->zero(m_windowSize/2); + } + } +} + + +void +RubberBandStretcher::Impl::reconfigure() +{ + if (!m_realtime) { + if (m_mode == Studying) { + // stop and calculate the stretch curve so far, then reset + // the df vectors + calculateStretch(); + m_phaseResetDf.clear(); + m_stretchDf.clear(); + m_inputDuration = 0; + } + configure(); + } + + size_t prevWindowSize = m_windowSize; + size_t prevOutbufSize = m_outbufSize; + + calculateSizes(); + + // There are various allocations in this function, but they should + // never happen in normal use -- they just recover from the case + // where not all of the things we need were correctly created when + // we first configured (for whatever reason). This is intended to + // be "effectively" realtime safe. The same goes for + // ChannelData::setOutbufSize and setWindowSize. + + if (m_windowSize != prevWindowSize) { + + if (m_windows.find(m_windowSize) == m_windows.end()) { + std::cerr << "WARNING: reconfigure(): window allocation (size " << m_windowSize << ") required in RT mode" << std::endl; + m_windows[m_windowSize] = new Window<float>(HanningWindow, m_windowSize); + } + m_window = m_windows[m_windowSize]; + + for (size_t c = 0; c < m_channels; ++c) { + m_channelData[c]->setWindowSize(m_windowSize); + } + } + + if (m_outbufSize != prevOutbufSize) { + for (size_t c = 0; c < m_channels; ++c) { + m_channelData[c]->setOutbufSize(m_outbufSize); + } + } + + if (m_pitchScale != 1.0) { + for (size_t c = 0; c < m_channels; ++c) { + + if (m_channelData[c]->resampler) continue; + + std::cerr << "WARNING: reconfigure(): resampler construction required in RT mode" << std::endl; + + m_channelData[c]->resampler = + new Resampler(Resampler::FastestTolerable, 1, m_windowSize); + + m_channelData[c]->resamplebufSize = + lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale)); + m_channelData[c]->resamplebuf = + new float[m_channelData[c]->resamplebufSize]; + } + } + + if (m_windowSize != prevWindowSize) { + m_phaseResetAudioCurve->setWindowSize(m_windowSize); + } +} + +size_t +RubberBandStretcher::Impl::getLatency() const +{ + if (!m_realtime) return 0; + return int((m_windowSize/2) / m_pitchScale + 1); +} + +void +RubberBandStretcher::Impl::setTransientsOption(Options options) +{ + if (!m_realtime) { + cerr << "RubberBandStretcher::Impl::setTransientsOption: Not permissible in non-realtime mode" << endl; + return; + } + m_options &= ~(OptionTransientsMixed | + OptionTransientsSmooth | + OptionTransientsCrisp); + m_options |= options; + + m_stretchCalculator->setUseHardPeaks + (!(m_options & OptionTransientsSmooth)); +} + +void +RubberBandStretcher::Impl::setPhaseOption(Options options) +{ + m_options &= ~(OptionPhaseAdaptive | + OptionPhasePeakLocked | + OptionPhaseIndependent); + m_options |= options; +} + +void +RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool final) +{ + if (m_realtime) { + if (m_debugLevel > 1) { + cerr << "RubberBandStretcher::Impl::study: Not meaningful in realtime mode" << endl; + } + return; + } + + if (m_mode == Processing || m_mode == Finished) { + cerr << "RubberBandStretcher::Impl::study: Cannot study after processing" << endl; + return; + } + m_mode = Studying; + + size_t consumed = 0; + + ChannelData &cd = *m_channelData[0]; + RingBuffer<float> &inbuf = *cd.inbuf; + + const float *mixdown; + float *mdalloc = 0; + + if (m_channels > 1 || final) { + // mix down into a single channel for analysis + mdalloc = new float[samples]; + for (size_t i = 0; i < samples; ++i) { + if (i < samples) { + mdalloc[i] = input[0][i]; + } else { + mdalloc[i] = 0.f; + } + } + for (size_t c = 1; c < m_channels; ++c) { + for (size_t i = 0; i < samples; ++i) { + mdalloc[i] += input[c][i]; + } + } + for (size_t i = 0; i < samples; ++i) { + mdalloc[i] /= m_channels; + } + mixdown = mdalloc; + } else { + mixdown = input[0]; + } + + while (consumed < samples) { + + size_t writable = inbuf.getWriteSpace(); + writable = min(writable, samples - consumed); + + if (writable == 0) { + // warn + cerr << "WARNING: writable == 0 (consumed = " << consumed << ", samples = " << samples << ")" << endl; + } else { + inbuf.write(mixdown + consumed, writable); + consumed += writable; + } + + while ((inbuf.getReadSpace() >= m_windowSize) || + (final && (inbuf.getReadSpace() >= m_windowSize/2))) { + + // We know we have at least m_windowSize samples available + // in m_inbuf. We need to peek m_windowSize of them for + // processing, and then skip m_increment to advance the + // read pointer. + + // cd.accumulator is not otherwise used during studying, + // so we can use it as a temporary buffer here + + size_t got = inbuf.peek(cd.accumulator, m_windowSize); + assert(final || got == m_windowSize); + + m_window->cut(cd.accumulator); + + // We don't need the fftshift for studying, as we're only + // interested in magnitude + + m_studyFFT->forwardMagnitude(cd.accumulator, cd.fltbuf); + + float df = m_phaseResetAudioCurve->process(cd.fltbuf, m_increment); + m_phaseResetDf.push_back(df); + +// cout << m_phaseResetDf.size() << " [" << final << "] -> " << df << " \t: "; + + df = m_stretchAudioCurve->process(cd.fltbuf, m_increment); + m_stretchDf.push_back(df); + +// cout << df << endl; + + // We have augmented the input by m_windowSize/2 so + // that the first chunk is centred on the first audio + // sample. We want to ensure that m_inputDuration + // contains the exact input duration without including + // this extra bit. We just add up all the increments + // here, and deduct the extra afterwards. + + m_inputDuration += m_increment; +// cerr << "incr input duration by increment: " << m_increment << " -> " << m_inputDuration << endl; + inbuf.skip(m_increment); + } + } + + if (final) { + int rs = inbuf.getReadSpace(); + m_inputDuration += rs; +// cerr << "incr input duration by read space: " << rs << " -> " << m_inputDuration << endl; + + if (m_inputDuration > m_windowSize/2) { // deducting the extra + m_inputDuration -= m_windowSize/2; + } + } + + if (m_channels > 1) delete[] mdalloc; +} + +vector<int> +RubberBandStretcher::Impl::getOutputIncrements() const +{ + if (!m_realtime) { + return m_outputIncrements; + } else { + vector<int> increments; + while (m_lastProcessOutputIncrements.getReadSpace() > 0) { + increments.push_back(m_lastProcessOutputIncrements.readOne()); + } + return increments; + } +} + +vector<float> +RubberBandStretcher::Impl::getPhaseResetCurve() const +{ + if (!m_realtime) { + return m_phaseResetDf; + } else { + vector<float> df; + while (m_lastProcessPhaseResetDf.getReadSpace() > 0) { + df.push_back(m_lastProcessPhaseResetDf.readOne()); + } + return df; + } +} + +vector<int> +RubberBandStretcher::Impl::getExactTimePoints() const +{ + std::vector<int> points; + if (!m_realtime) { + std::vector<StretchCalculator::Peak> peaks = + m_stretchCalculator->getLastCalculatedPeaks(); + for (size_t i = 0; i < peaks.size(); ++i) { + points.push_back(peaks[i].chunk); + } + } + return points; +} + +void +RubberBandStretcher::Impl::calculateStretch() +{ + std::vector<int> increments = m_stretchCalculator->calculate + (getEffectiveRatio(), + m_inputDuration, + m_phaseResetDf, + m_stretchDf); + + if (m_outputIncrements.empty()) m_outputIncrements = increments; + else { + for (size_t i = 0; i < increments.size(); ++i) { + m_outputIncrements.push_back(increments[i]); + } + } + + return; +} + +void +RubberBandStretcher::Impl::setDebugLevel(int level) +{ + m_debugLevel = level; + if (m_stretchCalculator) m_stretchCalculator->setDebugLevel(level); +} + +size_t +RubberBandStretcher::Impl::getSamplesRequired() const +{ + size_t reqd = 0; + + for (size_t c = 0; c < m_channels; ++c) { + + size_t reqdHere = 0; + + ChannelData &cd = *m_channelData[c]; + RingBuffer<float> &inbuf = *cd.inbuf; + + size_t rs = inbuf.getReadSpace(); + + // See notes in testInbufReadSpace + + if (rs < m_windowSize && !cd.draining) { + + if (cd.inputSize == -1) { + reqdHere = m_windowSize - rs; + if (reqdHere > reqd) reqd = reqdHere; + continue; + } + + if (rs == 0) { + reqdHere = m_windowSize; + if (reqdHere > reqd) reqd = reqdHere; + continue; + } + } + } + + return reqd; +} + +void +RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bool final) +{ + if (m_mode == Finished) { + cerr << "RubberBandStretcher::Impl::process: Cannot process again after final chunk" << endl; + return; + } + + if (m_mode == JustCreated || m_mode == Studying) { + + if (m_mode == Studying) { + calculateStretch(); + } + + for (size_t c = 0; c < m_channels; ++c) { + m_channelData[c]->reset(); + m_channelData[c]->inbuf->zero(m_windowSize/2); + } + + if (m_threaded) { + MutexLocker locker(&m_threadSetMutex); + + for (size_t c = 0; c < m_channels; ++c) { + ProcessThread *thread = new ProcessThread(this, c); + m_threadSet.insert(thread); + thread->start(); + } + + if (m_debugLevel > 0) { + cerr << m_channels << " threads created" << endl; + } + } + + m_mode = Processing; + } + + bool allConsumed = false; + + map<size_t, size_t> consumed; + for (size_t c = 0; c < m_channels; ++c) { + consumed[c] = 0; + } + + while (!allConsumed) { + +// cerr << "process looping" << endl; + +//#ifndef NO_THREADING +// if (m_threaded) { +// pthread_mutex_lock(&m_inputProcessedMutex); +// } +//#endif + + // In a threaded mode, our "consumed" counters only indicate + // the number of samples that have been taken into the input + // ring buffers waiting to be processed by the process thread. + // In non-threaded mode, "consumed" counts the number that + // have actually been processed. + + allConsumed = true; + for (size_t c = 0; c < m_channels; ++c) { + consumed[c] += consumeChannel(c, + input[c] + consumed[c], + samples - consumed[c]); + if (consumed[c] < samples) { + allConsumed = false; +// cerr << "process: waiting on input consumption for channel " << c << endl; + } else { + if (final) { + m_channelData[c]->inputSize = m_channelData[c]->inCount; + } +// cerr << "process: happy with channel " << c << endl; + } + if (!m_threaded && !m_realtime) { + bool any = false, last = false; + processChunks(c, any, last); + } + } + + if (m_realtime) { + // When running in real time, we need to process both + // channels in step because we will need to use the sum of + // their frequency domain representations as the input to + // the realtime onset detector + processOneChunk(); + } + + if (m_threaded) { + for (ThreadSet::iterator i = m_threadSet.begin(); + i != m_threadSet.end(); ++i) { + (*i)->signalDataAvailable(); + } + if (!allConsumed) { + m_spaceAvailable.wait(500); + } +/* + } else { + if (!allConsumed) { + cerr << "RubberBandStretcher::Impl::process: ERROR: Too much data provided to process() call -- either call setMaxProcessSize() beforehand, or provide only getSamplesRequired() frames at a time" << endl; + for (size_t c = 0; c < m_channels; ++c) { + cerr << "channel " << c << ": " << samples << " provided, " << consumed[c] << " consumed" << endl; + } +// break; + } +*/ + } + } + +// cerr << "process returning" << endl; + + if (final) m_mode = Finished; +} + +size_t +RubberBandStretcher::Impl::consumeChannel(size_t c, const float *input, size_t samples) +{ + size_t consumed = 0; + + ChannelData &cd = *m_channelData[c]; + RingBuffer<float> &inbuf = *cd.inbuf; + + while (consumed < samples) { + + size_t writable = inbuf.getWriteSpace(); + +// cerr << "channel " << c << ": samples remaining = " << samples - consumed << ", writable space = " << writable << endl; + + writable = min(writable, samples - consumed); + + if (writable == 0) { + // warn +// cerr << "WARNING: writable == 0 for ch " << c << " (consumed = " << consumed << ", samples = " << samples << ")" << endl; + return consumed; + } else { + inbuf.write(input + consumed, writable); + consumed += writable; + cd.inCount += writable; + } + } + + return samples; +} + + +} + diff --git a/libs/rubberband/1.0/src/StretcherImpl.h b/libs/rubberband/1.0/src/StretcherImpl.h new file mode 100644 index 0000000000..0dec4aa245 --- /dev/null +++ b/libs/rubberband/1.0/src/StretcherImpl.h @@ -0,0 +1,194 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_STRETCHERIMPL_H_ +#define _RUBBERBAND_STRETCHERIMPL_H_ + +#include "RubberBandStretcher.h" + +#include "Window.h" +#include "Thread.h" +#include "RingBuffer.h" +#include "FFT.h" +#include "sysutils.h" + +#include <set> + +namespace RubberBand +{ + +class AudioCurve; +class StretchCalculator; + +class RubberBandStretcher::Impl +{ +public: + Impl(RubberBandStretcher *stretcher, + size_t sampleRate, size_t channels, Options options, + double initialTimeRatio, double initialPitchScale); + ~Impl(); + + void reset(); + void setTimeRatio(double ratio); + void setPitchScale(double scale); + + double getTimeRatio() const; + double getPitchScale() const; + + size_t getLatency() const; + + void setTransientsOption(Options); + void setPhaseOption(Options); + + void setExpectedInputDuration(size_t samples); + void setMaxProcessSize(size_t samples); + + size_t getSamplesRequired() const; + + void study(const float *const *input, size_t samples, bool final); + void process(const float *const *input, size_t samples, bool final); + + int available() const; + size_t retrieve(float *const *output, size_t samples) const; + + float getFrequencyCutoff(int n) const; + void setFrequencyCutoff(int n, float f); + + size_t getInputIncrement() const { + return m_increment; + } + + std::vector<int> getOutputIncrements() const; + std::vector<float> getPhaseResetCurve() const; + std::vector<int> getExactTimePoints() const; + + size_t getChannelCount() const { + return m_channels; + } + + void calculateStretch(); + + void setDebugLevel(int level); + static void setDefaultDebugLevel(int level) { m_defaultDebugLevel = level; } + +protected: + RubberBandStretcher *m_stretcher; + size_t m_channels; + + size_t consumeChannel(size_t channel, const float *input, size_t samples); + void processChunks(size_t channel, bool &any, bool &last); + bool processOneChunk(); // across all channels, for real time use + bool processChunkForChannel(size_t channel, size_t phaseIncrement, + size_t shiftIncrement, bool phaseReset); + bool testInbufReadSpace(size_t channel); + void calculateIncrements(size_t &phaseIncrement, + size_t &shiftIncrement, bool &phaseReset); + bool getIncrements(size_t channel, size_t &phaseIncrement, + size_t &shiftIncrement, bool &phaseReset); + void analyseChunk(size_t channel); + void modifyChunk(size_t channel, size_t outputIncrement, bool phaseReset); + void synthesiseChunk(size_t channel); + void writeChunk(size_t channel, size_t shiftIncrement, bool last); + + void calculateSizes(); + void configure(); + void reconfigure(); + + double getEffectiveRatio() const; + + size_t roundUp(size_t value); // to next power of two + + double m_timeRatio; + double m_pitchScale; + + size_t m_windowSize; + size_t m_increment; + size_t m_outbufSize; + + size_t m_maxProcessSize; + size_t m_expectedInputDuration; + + bool m_threaded; + bool m_realtime; + Options m_options; + int m_debugLevel; + + enum ProcessMode { + JustCreated, + Studying, + Processing, + Finished + }; + + ProcessMode m_mode; + + std::map<size_t, Window<float> *> m_windows; + Window<float> *m_window; + FFT *m_studyFFT; + + Condition m_spaceAvailable; + + class ProcessThread : public Thread + { + public: + ProcessThread(Impl *s, size_t c); + void run(); + void signalDataAvailable(); + void abandon(); + private: + Impl *m_s; + size_t m_channel; + Condition m_dataAvailable; + bool m_abandoning; + }; + + mutable Mutex m_threadSetMutex; + typedef std::set<ProcessThread *> ThreadSet; + ThreadSet m_threadSet; + + + size_t m_inputDuration; + std::vector<float> m_phaseResetDf; + std::vector<float> m_stretchDf; + + class ChannelData; + std::vector<ChannelData *> m_channelData; + + std::vector<int> m_outputIncrements; + + mutable RingBuffer<int> m_lastProcessOutputIncrements; + mutable RingBuffer<float> m_lastProcessPhaseResetDf; + + AudioCurve *m_phaseResetAudioCurve; + AudioCurve *m_stretchAudioCurve; + StretchCalculator *m_stretchCalculator; + + float m_freq0; + float m_freq1; + float m_freq2; + + size_t m_baseWindowSize; + float m_rateMultiple; + + void writeOutput(RingBuffer<float> &to, float *from, + size_t qty, size_t &outCount, size_t theoreticalOut); + + static int m_defaultDebugLevel; + static const size_t m_defaultIncrement; + static const size_t m_defaultWindowSize; +}; + +} + +#endif diff --git a/libs/rubberband/1.0/src/StretcherProcess.cpp b/libs/rubberband/1.0/src/StretcherProcess.cpp new file mode 100644 index 0000000000..1e8e7d1afb --- /dev/null +++ b/libs/rubberband/1.0/src/StretcherProcess.cpp @@ -0,0 +1,927 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "StretcherImpl.h" +#include "PercussiveAudioCurve.h" +#include "HighFrequencyAudioCurve.h" +#include "ConstantAudioCurve.h" +#include "StretchCalculator.h" +#include "StretcherChannelData.h" +#include "Resampler.h" + +#include <cassert> +#include <cmath> +#include <set> +#include <map> + +using std::cerr; +using std::endl; + +namespace RubberBand { + +RubberBandStretcher::Impl::ProcessThread::ProcessThread(Impl *s, size_t c) : + m_s(s), + m_channel(c), + m_dataAvailable(std::string("data ") + char('A' + c)), + m_abandoning(false) +{ } + +void +RubberBandStretcher::Impl::ProcessThread::run() +{ + if (m_s->m_debugLevel > 1) { + cerr << "thread " << m_channel << " getting going" << endl; + } + + ChannelData &cd = *m_s->m_channelData[m_channel]; + + while (cd.inputSize == -1 || + cd.inbuf->getReadSpace() > 0) { + +// if (cd.inputSize != -1) { +// cerr << "inputSize == " << cd.inputSize +// << ", readSpace == " << cd.inbuf->getReadSpace() << endl; +// } + + bool any = false, last = false; + m_s->processChunks(m_channel, any, last); + + if (last) break; + + if (any) m_s->m_spaceAvailable.signal(); + + m_dataAvailable.lock(); + if (!m_s->testInbufReadSpace(m_channel) && !m_abandoning) { + m_dataAvailable.wait(); + } else { + m_dataAvailable.unlock(); + } + + if (m_abandoning) { + if (m_s->m_debugLevel > 1) { + cerr << "thread " << m_channel << " abandoning" << endl; + } + return; + } + } + + bool any = false, last = false; + m_s->processChunks(m_channel, any, last); + m_s->m_spaceAvailable.signal(); + + if (m_s->m_debugLevel > 1) { + cerr << "thread " << m_channel << " done" << endl; + } +} + +void +RubberBandStretcher::Impl::ProcessThread::signalDataAvailable() +{ + m_dataAvailable.signal(); +} + +void +RubberBandStretcher::Impl::ProcessThread::abandon() +{ + m_abandoning = true; +} + +void +RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last) +{ + // Process as many chunks as there are available on the input + // buffer for channel c. This requires that the increments have + // already been calculated. + + ChannelData &cd = *m_channelData[c]; + + last = false; + any = false; + + while (!last) { + + if (!testInbufReadSpace(c)) { +// cerr << "not enough input" << endl; + break; + } + + any = true; + + if (!cd.draining) { + size_t got = cd.inbuf->peek(cd.fltbuf, m_windowSize); + assert(got == m_windowSize || cd.inputSize >= 0); + cd.inbuf->skip(m_increment); + analyseChunk(c); + } + + bool phaseReset = false; + size_t phaseIncrement, shiftIncrement; + getIncrements(c, phaseIncrement, shiftIncrement, phaseReset); + + last = processChunkForChannel(c, phaseIncrement, shiftIncrement, phaseReset); + cd.chunkCount++; + if (m_debugLevel > 2) { + cerr << "channel " << c << ": last = " << last << ", chunkCount = " << cd.chunkCount << endl; + } + } +} + +bool +RubberBandStretcher::Impl::processOneChunk() +{ + // Process a single chunk for all channels, provided there is + // enough data on each channel for at least one chunk. This is + // able to calculate increments as it goes along. + + for (size_t c = 0; c < m_channels; ++c) { + if (!testInbufReadSpace(c)) return false; + ChannelData &cd = *m_channelData[c]; + if (!cd.draining) { + size_t got = cd.inbuf->peek(cd.fltbuf, m_windowSize); + assert(got == m_windowSize || cd.inputSize >= 0); + cd.inbuf->skip(m_increment); + analyseChunk(c); + } + } + + bool phaseReset = false; + size_t phaseIncrement, shiftIncrement; + if (!getIncrements(0, phaseIncrement, shiftIncrement, phaseReset)) { + calculateIncrements(phaseIncrement, shiftIncrement, phaseReset); + } + + bool last = false; + for (size_t c = 0; c < m_channels; ++c) { + last = processChunkForChannel(c, phaseIncrement, shiftIncrement, phaseReset); + m_channelData[c]->chunkCount++; + } + + return last; +} + +bool +RubberBandStretcher::Impl::testInbufReadSpace(size_t c) +{ + ChannelData &cd = *m_channelData[c]; + RingBuffer<float> &inbuf = *cd.inbuf; + + size_t rs = inbuf.getReadSpace(); + + if (rs < m_windowSize && !cd.draining) { + + if (cd.inputSize == -1) { + + // Not all the input data has been written to the inbuf + // (that's why the input size is not yet set). We can't + // process, because we don't have a full chunk of data, so + // our process chunk would contain some empty padding in + // its input -- and that would give incorrect output, as + // we know there is more input to come. + + if (!m_threaded) { +// cerr << "WARNING: RubberBandStretcher: read space < chunk size (" +// << inbuf.getReadSpace() << " < " << m_windowSize +// << ") when not all input written, on processChunks for channel " << c << endl; + } + return false; + } + + if (rs == 0) { + + if (m_debugLevel > 1) { + cerr << "read space = 0, giving up" << endl; + } + return false; + + } else if (rs < m_windowSize/2) { + + if (m_debugLevel > 1) { + cerr << "read space = " << rs << ", setting draining true" << endl; + } + + cd.draining = true; + } + } + + return true; +} + +bool +RubberBandStretcher::Impl::processChunkForChannel(size_t c, + size_t phaseIncrement, + size_t shiftIncrement, + bool phaseReset) +{ + // Process a single chunk on a single channel. This assumes + // enough input data is available; caller must have tested this + // using e.g. testInbufReadSpace first. Return true if this is + // the last chunk on the channel. + + if (phaseReset && (m_debugLevel > 1)) { + cerr << "processChunkForChannel: phase reset found, incrs " + << phaseIncrement << ":" << shiftIncrement << endl; + } + + ChannelData &cd = *m_channelData[c]; + + if (!cd.draining) { + + // This is the normal processing case -- draining is only + // set when all the input has been used and we only need + // to write from the existing accumulator into the output. + + // We know we have enough samples available in m_inbuf -- + // this is usually m_windowSize, but we know that if fewer + // are available, it's OK to use zeroes for the rest + // (which the ring buffer will provide) because we've + // reached the true end of the data. + + // We need to peek m_windowSize samples for processing, and + // then skip m_increment to advance the read pointer. + + modifyChunk(c, phaseIncrement, phaseReset); + synthesiseChunk(c); // reads from cd.mag, cd.phase + + if (m_debugLevel > 2) { + if (phaseReset) { + for (int i = 0; i < 10; ++i) { + cd.accumulator[i] = 1.2f - (i % 3) * 1.2f; + } + } + } + } + + bool last = false; + + if (cd.draining) { + if (m_debugLevel > 1) { + cerr << "draining: accumulator fill = " << cd.accumulatorFill << " (shiftIncrement = " << shiftIncrement << ")" << endl; + } + if (shiftIncrement == 0) { + cerr << "WARNING: draining: shiftIncrement == 0, can't handle that in this context: setting to " << m_increment << endl; + shiftIncrement = m_increment; + } + if (cd.accumulatorFill <= shiftIncrement) { + if (m_debugLevel > 1) { + cerr << "reducing shift increment from " << shiftIncrement + << " to " << cd.accumulatorFill + << " and marking as last" << endl; + } + shiftIncrement = cd.accumulatorFill; + last = true; + } + } + + if (m_threaded) { + size_t required = shiftIncrement; + if (m_pitchScale != 1.0) { + required = int(required / m_pitchScale) + 1; + } + + if (cd.outbuf->getWriteSpace() < required) { + if (m_debugLevel > 0) { + cerr << "Buffer overrun on output for channel " << c << endl; + } + + //!!! The only correct thing we can do here is resize the + // buffer. We can't wait for the client thread to read + // some data out from the buffer so as to make more space, + // because the client thread is probably stuck in a + // process() call waiting for us to stow away enough input + // increments to allow the process() call to complete. + + } + } + + writeChunk(c, shiftIncrement, last); + return last; +} + +void +RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn, + size_t &shiftIncrementRtn, + bool &phaseReset) +{ +// cerr << "calculateIncrements" << endl; + + // Calculate the next upcoming phase and shift increment, on the + // basis that both channels are in sync. This is in contrast to + // getIncrements, which requires that all the increments have been + // calculated in advance but can then return increments + // corresponding to different chunks in different channels. + + // Requires frequency domain representations of channel data in + // the mag and phase buffers in the channel. + + // This function is only used in real-time mode. + + phaseIncrementRtn = m_increment; + shiftIncrementRtn = m_increment; + phaseReset = false; + + if (m_channels == 0) return; + + ChannelData &cd = *m_channelData[0]; + + size_t bc = cd.chunkCount; + for (size_t c = 1; c < m_channels; ++c) { + if (m_channelData[c]->chunkCount != bc) { + cerr << "ERROR: RubberBandStretcher::Impl::calculateIncrements: Channels are not in sync" << endl; + return; + } + } + + // Normally we would mix down the time-domain signal and apply a + // single FFT, or else mix down the Cartesian form of the + // frequency-domain signal. Both of those would be inefficient + // from this position. Fortunately, the onset detectors should + // work reasonably well (maybe even better?) if we just sum the + // magnitudes of the frequency-domain channel signals and forget + // about phase entirely. Normally we don't expect the channel + // phases to cancel each other, and broadband effects will still + // be apparent. + + for (size_t i = 0; i <= m_windowSize/2; ++i) { + cd.fltbuf[i] = 0.0; + } + + for (size_t c = 0; c < m_channels; ++c) { + for (size_t i = 0; i <= m_windowSize/2; ++i) { + cd.fltbuf[i] += m_channelData[c]->mag[i]; + } + } + + float df = m_phaseResetAudioCurve->process(cd.fltbuf, m_increment); + + int incr = m_stretchCalculator->calculateSingle + (getEffectiveRatio(), + m_inputDuration, //!!! no, totally wrong... fortunately it doesn't matter atm + df); + + m_lastProcessPhaseResetDf.write(&df, 1); + m_lastProcessOutputIncrements.write(&incr, 1); + + if (incr < 0) { + phaseReset = true; + incr = -incr; + } + + // The returned increment is the phase increment. The shift + // increment for one chunk is the same as the phase increment for + // the following chunk (see comment below). This means we don't + // actually know the shift increment until we see the following + // phase increment... which is a bit of a problem. + + // This implies we should use this increment for the shift + // increment, and make the following phase increment the same as + // it. This means in RT mode we'll be one chunk later with our + // phase reset than we would be in non-RT mode. The sensitivity + // of the broadband onset detector may mean that this isn't a + // problem -- test it and see. + + shiftIncrementRtn = incr; + + if (cd.prevIncrement == 0) { + phaseIncrementRtn = shiftIncrementRtn; + } else { + phaseIncrementRtn = cd.prevIncrement; + } + + cd.prevIncrement = shiftIncrementRtn; +} + +bool +RubberBandStretcher::Impl::getIncrements(size_t channel, + size_t &phaseIncrementRtn, + size_t &shiftIncrementRtn, + bool &phaseReset) +{ + if (channel >= m_channels) { + phaseIncrementRtn = m_increment; + shiftIncrementRtn = m_increment; + phaseReset = false; + return false; + } + + // There are two relevant output increments here. The first is + // the phase increment which we use when recalculating the phases + // for the current chunk; the second is the shift increment used + // to determine how far to shift the processing buffer after + // writing the chunk. The shift increment for one chunk is the + // same as the phase increment for the following chunk. + + // When an onset occurs for which we need to reset phases, the + // increment given will be negative. + + // When we reset phases, the previous shift increment (and so + // current phase increments) must have been m_increment to ensure + // consistency. + + // m_outputIncrements stores phase increments. + + ChannelData &cd = *m_channelData[channel]; + bool gotData = true; + + if (cd.chunkCount >= m_outputIncrements.size()) { +// cerr << "WARNING: RubberBandStretcher::Impl::getIncrements:" +// << " chunk count " << cd.chunkCount << " >= " +// << m_outputIncrements.size() << endl; + if (m_outputIncrements.size() == 0) { + phaseIncrementRtn = m_increment; + shiftIncrementRtn = m_increment; + phaseReset = false; + return false; + } else { + cd.chunkCount = m_outputIncrements.size()-1; + gotData = false; + } + } + + int phaseIncrement = m_outputIncrements[cd.chunkCount]; + + int shiftIncrement = phaseIncrement; + if (cd.chunkCount + 1 < m_outputIncrements.size()) { + shiftIncrement = m_outputIncrements[cd.chunkCount + 1]; + } + + if (phaseIncrement < 0) { + phaseIncrement = -phaseIncrement; + phaseReset = true; + } + + if (shiftIncrement < 0) { + shiftIncrement = -shiftIncrement; + } + + if (shiftIncrement >= int(m_windowSize)) { + cerr << "*** ERROR: RubberBandStretcher::Impl::processChunks: shiftIncrement " << shiftIncrement << " >= windowSize " << m_windowSize << " at " << cd.chunkCount << " (of " << m_outputIncrements.size() << ")" << endl; + shiftIncrement = m_windowSize; + } + + phaseIncrementRtn = phaseIncrement; + shiftIncrementRtn = shiftIncrement; + if (cd.chunkCount == 0) phaseReset = true; // don't mess with the first chunk + return gotData; +} + +void +RubberBandStretcher::Impl::analyseChunk(size_t channel) +{ + size_t i; + + ChannelData &cd = *m_channelData[channel]; + + // cd.fltbuf is known to contain m_windowSize samples + + m_window->cut(cd.fltbuf); + + for (i = 0; i < m_windowSize/2; ++i) { + cd.dblbuf[i] = cd.fltbuf[i + m_windowSize/2]; + cd.dblbuf[i + m_windowSize/2] = cd.fltbuf[i]; + } + + cd.fft->forwardPolar(cd.dblbuf, cd.mag, cd.phase); +} + +double mod(double x, double y) { return x - (y * floor(x / y)); } +double princarg(double a) { return mod(a + M_PI, -2 * M_PI) + M_PI; } + +void +RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement, + bool phaseReset) +{ + ChannelData &cd = *m_channelData[channel]; + + if (phaseReset && m_debugLevel > 1) { + cerr << "phase reset: leaving phases unmodified" << endl; + } + + size_t count = m_windowSize/2; + size_t pfp = 0; + double rate = m_stretcher->m_sampleRate; + + if (!(m_options & OptionPhaseIndependent)) { + + cd.freqPeak[0] = 0; + + float freq0 = m_freq0; + float freq1 = m_freq1; + float freq2 = m_freq2; + + // As the stretch ratio increases, so the frequency thresholds + // for phase lamination should increase. Beyond a ratio of + // about 1.5, the threshold should be about 1200Hz; beyond a + // ratio of 2, we probably want no lamination to happen at all + // by default. This calculation aims for more or less that. + // We only do this if the phase option is OptionPhaseAdaptive + // (the default), i.e. not Independent or PeakLocked. + + if (!(m_options & OptionPhasePeakLocked)) { + float r = getEffectiveRatio(); + if (r > 1) { + float rf0 = 600 + (600 * ((r-1)*(r-1)*(r-1)*2)); + float f1ratio = freq1 / freq0; + float f2ratio = freq2 / freq0; + freq0 = std::max(freq0, rf0); + freq1 = freq0 * f1ratio; + freq2 = freq0 * f2ratio; + } + } + + size_t limit0 = lrint((freq0 * m_windowSize) / rate); + size_t limit1 = lrint((freq1 * m_windowSize) / rate); + size_t limit2 = lrint((freq2 * m_windowSize) / rate); + + size_t range = 0; + + if (limit1 < limit0) limit1 = limit0; + if (limit2 < limit1) limit2 = limit1; + +// cerr << "limit0 = " << limit0 << " limit1 = " << limit1 << " limit2 = " << limit2 << endl; + + int peakCount = 0; + + for (size_t i = 0; i <= count; ++i) { + + double mag = cd.mag[i]; + bool isPeak = true; + + for (size_t j = 1; j <= range; ++j) { + + if (mag < cd.mag[i-j]) { + isPeak = false; + break; + } + + if (mag < cd.mag[i+j]) { + isPeak = false; + break; + } + } + + if (isPeak) { + + // i is a peak bin. + + // The previous peak bin was at pfp; make freqPeak entries + // from pfp to half-way between pfp and i point at pfp, and + // those from the half-way mark to i point at i. + + size_t halfway = (pfp + i) / 2; + if (halfway == pfp) halfway = pfp + 1; + + for (size_t j = pfp + 1; j < halfway; ++j) { + cd.freqPeak[j] = pfp; + } + for (size_t j = halfway; j <= i; ++j) { + cd.freqPeak[j] = i; + } + + pfp = i; + + ++peakCount; + } + + if (i == limit0) range = 1; + if (i == limit1) range = 2; + if (i >= limit2) { + range = 3; + if (i + range + 1 > count) range = count - i; + } + } + +// cerr << "peakCount = " << peakCount << endl; + + cd.freqPeak[count-1] = count-1; + cd.freqPeak[count] = count; + } + + double peakInPhase = 0.0; + double peakOutPhase = 0.0; + size_t p, pp; + + for (size_t i = 0; i <= count; ++i) { + + if (m_options & OptionPhaseIndependent) { + p = i; + pp = i-1; + } else { + p = cd.freqPeak[i]; + pp = cd.freqPeak[i-1]; + } + + bool resetThis = phaseReset; + + if (m_options & OptionTransientsMixed) { + size_t low = lrint((150 * m_windowSize) / rate); + size_t high = lrint((1000 * m_windowSize) / rate); + if (resetThis) { + if (i > low && i < high) resetThis = false; + } + } + + if (!resetThis) { + + if (i == 0 || p != pp) { + + double omega = (2 * M_PI * m_increment * p) / m_windowSize; + double expectedPhase = cd.prevPhase[p] + omega; + double phaseError = princarg(cd.phase[p] - expectedPhase); + double phaseIncrement = (omega + phaseError) / m_increment; + + double unwrappedPhase = cd.unwrappedPhase[p] + + outputIncrement * phaseIncrement; + + cd.prevPhase[p] = cd.phase[p]; + cd.phase[p] = unwrappedPhase; + cd.unwrappedPhase[p] = unwrappedPhase; + + peakInPhase = cd.prevPhase[p]; + peakOutPhase = unwrappedPhase; + } + + if (i != p) { + + double diffToPeak = peakInPhase - cd.phase[i]; + double unwrappedPhase = peakOutPhase - diffToPeak; + + cd.prevPhase[i] = cd.phase[i]; + cd.phase[i] = unwrappedPhase; + cd.unwrappedPhase[i] = unwrappedPhase; + } + + } else { + cd.prevPhase[i] = cd.phase[i]; + cd.unwrappedPhase[i] = cd.phase[i]; + } + } +} + +void +RubberBandStretcher::Impl::synthesiseChunk(size_t channel) +{ + ChannelData &cd = *m_channelData[channel]; + + cd.fft->inversePolar(cd.mag, cd.phase, cd.dblbuf); + + for (size_t i = 0; i < m_windowSize/2; ++i) { + cd.fltbuf[i] = cd.dblbuf[i + m_windowSize/2]; + cd.fltbuf[i + m_windowSize/2] = cd.dblbuf[i]; + } + + // our ffts produced unscaled results + for (size_t i = 0; i < m_windowSize; ++i) { + cd.fltbuf[i] = cd.fltbuf[i] / m_windowSize; + } + + m_window->cut(cd.fltbuf); + + for (size_t i = 0; i < m_windowSize; ++i) { + cd.accumulator[i] += cd.fltbuf[i]; + } + + cd.accumulatorFill = m_windowSize; + + float fixed = m_window->getArea() * 1.5; + + for (size_t i = 0; i < m_windowSize; ++i) { + float val = m_window->getValue(i); + cd.windowAccumulator[i] += val * fixed; + } +} + +void +RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, bool last) +{ + ChannelData &cd = *m_channelData[channel]; + + if (m_debugLevel > 2) { + cerr << "writeChunk(" << channel << ", " << shiftIncrement << ", " << last << ")" << endl; + } + + for (int i = 0; i < shiftIncrement; ++i) { + if (cd.windowAccumulator[i] > 0.f) { + cd.accumulator[i] /= cd.windowAccumulator[i]; + } + } + + // for exact sample scaling (probably not meaningful if we + // were running in RT mode) + size_t theoreticalOut = 0; + if (cd.inputSize >= 0) { + theoreticalOut = lrint(cd.inputSize * m_timeRatio); + } + + if (m_pitchScale != 1.0 && cd.resampler) { + + size_t reqSize = int(ceil(shiftIncrement / m_pitchScale)); + if (reqSize > cd.resamplebufSize) { + // This shouldn't normally happen -- the buffer is + // supposed to be initialised with enough space in the + // first place. But we retain this check in case the + // pitch scale has changed since then, or the stretch + // calculator has gone mad, or something. + cerr << "WARNING: RubberBandStretcher::Impl::writeChunk: resizing resampler buffer from " + << cd.resamplebufSize << " to " << reqSize << endl; + cd.resamplebufSize = reqSize; + if (cd.resamplebuf) delete[] cd.resamplebuf; + cd.resamplebuf = new float[cd.resamplebufSize]; + } + + + size_t outframes = cd.resampler->resample(&cd.accumulator, + &cd.resamplebuf, + shiftIncrement, + 1.0 / m_pitchScale, + last); + + + writeOutput(*cd.outbuf, cd.resamplebuf, + outframes, cd.outCount, theoreticalOut); + + } else { + writeOutput(*cd.outbuf, cd.accumulator, + shiftIncrement, cd.outCount, theoreticalOut); + } + + for (size_t i = 0; i < m_windowSize - shiftIncrement; ++i) { + cd.accumulator[i] = cd.accumulator[i + shiftIncrement]; + } + + for (size_t i = m_windowSize - shiftIncrement; i < m_windowSize; ++i) { + cd.accumulator[i] = 0.0f; + } + + for (size_t i = 0; i < m_windowSize - shiftIncrement; ++i) { + cd.windowAccumulator[i] = cd.windowAccumulator[i + shiftIncrement]; + } + + for (size_t i = m_windowSize - shiftIncrement; i < m_windowSize; ++i) { + cd.windowAccumulator[i] = 0.0f; + } + + if (cd.accumulatorFill > shiftIncrement) { + cd.accumulatorFill -= shiftIncrement; + } else { + cd.accumulatorFill = 0; + if (cd.draining) { + if (m_debugLevel > 1) { + cerr << "RubberBandStretcher::Impl::processChunks: setting outputComplete to true" << endl; + } + cd.outputComplete = true; + } + } +} + +void +RubberBandStretcher::Impl::writeOutput(RingBuffer<float> &to, float *from, size_t qty, size_t &outCount, size_t theoreticalOut) +{ + // In non-RT mode, we don't want to write the first startSkip + // samples, because the first chunk is centred on the start of the + // output. In RT mode we didn't apply any pre-padding in + // configure(), so we don't want to remove any here. + + size_t startSkip = 0; + if (!m_realtime) { + startSkip = lrintf((m_windowSize/2) / m_pitchScale); + } + + if (outCount > startSkip) { + + // this is the normal case + + if (theoreticalOut > 0) { + if (m_debugLevel > 1) { + cerr << "theoreticalOut = " << theoreticalOut + << ", outCount = " << outCount + << ", startSkip = " << startSkip + << ", qty = " << qty << endl; + } + if (outCount - startSkip <= theoreticalOut && + outCount - startSkip + qty > theoreticalOut) { + qty = theoreticalOut - (outCount - startSkip); + if (m_debugLevel > 1) { + cerr << "reduce qty to " << qty << endl; + } + } + } + + if (m_debugLevel > 2) { + cerr << "writing " << qty << endl; + } + + size_t written = to.write(from, qty); + + if (written < qty) { + cerr << "WARNING: RubberBandStretcher::Impl::writeOutput: " + << "Buffer overrun on output: wrote " << written + << " of " << qty << " samples" << endl; + } + + outCount += written; + return; + } + + // the rest of this is only used during the first startSkip samples + + if (outCount + qty <= startSkip) { + if (m_debugLevel > 1) { + cerr << "qty = " << qty << ", startSkip = " + << startSkip << ", outCount = " << outCount + << ", discarding" << endl; + } + outCount += qty; + return; + } + + size_t off = startSkip - outCount; + if (m_debugLevel > 1) { + cerr << "qty = " << qty << ", startSkip = " + << startSkip << ", outCount = " << outCount + << ", writing " << qty - off + << " from start offset " << off << endl; + } + to.write(from + off, qty - off); + outCount += qty; +} + +int +RubberBandStretcher::Impl::available() const +{ + if (m_threaded) { + MutexLocker locker(&m_threadSetMutex); + if (m_channelData.empty()) return 0; + } else { + if (m_channelData.empty()) return 0; + } + + if (!m_threaded) { + for (size_t c = 0; c < m_channels; ++c) { + if (m_channelData[c]->inputSize >= 0) { +// cerr << "available: m_done true" << endl; + if (m_channelData[c]->inbuf->getReadSpace() > 0) { +// cerr << "calling processChunks(" << c << ") from available" << endl; + //!!! do we ever actually do this? if so, this method should not be const + // ^^^ yes, we do sometimes -- e.g. when fed a very short file + bool any = false, last = false; + ((RubberBandStretcher::Impl *)this)->processChunks(c, any, last); + } + } + } + } + + size_t min = 0; + bool consumed = true; + bool haveResamplers = false; + + for (size_t i = 0; i < m_channels; ++i) { + size_t availIn = m_channelData[i]->inbuf->getReadSpace(); + size_t availOut = m_channelData[i]->outbuf->getReadSpace(); + if (m_debugLevel > 2) { + cerr << "available on channel " << i << ": " << availOut << " (waiting: " << availIn << ")" << endl; + } + if (i == 0 || availOut < min) min = availOut; + if (!m_channelData[i]->outputComplete) consumed = false; + if (m_channelData[i]->resampler) haveResamplers = true; + } + + if (min == 0 && consumed) return -1; + if (m_pitchScale == 1.0) return min; + + if (haveResamplers) return min; // resampling has already happened + return int(floor(min / m_pitchScale)); +} + +size_t +RubberBandStretcher::Impl::retrieve(float *const *output, size_t samples) const +{ + size_t got = samples; + + for (size_t c = 0; c < m_channels; ++c) { + size_t gotHere = m_channelData[c]->outbuf->read(output[c], got); + if (gotHere < got) { + if (c > 0) { + if (m_debugLevel > 0) { + cerr << "RubberBandStretcher::Impl::retrieve: WARNING: channel imbalance detected" << endl; + } + } + got = gotHere; + } + } + + return got; +} + +} + diff --git a/libs/rubberband/1.0/src/Thread.cpp b/libs/rubberband/1.0/src/Thread.cpp new file mode 100644 index 0000000000..2b37875f01 --- /dev/null +++ b/libs/rubberband/1.0/src/Thread.cpp @@ -0,0 +1,530 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "Thread.h" + +#include <iostream> + +#include <sys/time.h> +#include <time.h> + +//#define DEBUG_THREAD 1 +//#define DEBUG_MUTEX 1 +//#define DEBUG_CONDITION 1 + +using std::cerr; +using std::endl; +using std::string; + +namespace RubberBand +{ + +#ifdef _WIN32 + +Thread::Thread() : + m_id(0), + m_extant(false) +{ +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Created thread object " << this << endl; +#endif +} + +Thread::~Thread() +{ +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Destroying thread object " << this << ", id " << m_id << endl; +#endif + if (m_extant) { + WaitForSingleObject(m_id, INFINITE); + } +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Destroyed thread object " << this << endl; +#endif +} + +void +Thread::start() +{ + m_id = CreateThread(NULL, 0, staticRun, this, 0, 0); + if (!m_id) { + cerr << "ERROR: thread creation failed" << endl; + exit(1); + } else { +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Created thread " << m_id << " for thread object " << this << endl; +#endif + m_extant = true; + } +} + +void +Thread::wait() +{ + if (m_extant) { +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Waiting on thread " << m_id << " for thread object " << this << endl; +#endif + WaitForSingleObject(m_id, INFINITE); +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Waited on thread " << m_id << " for thread object " << this << endl; +#endif + m_extant = false; + } +} + +Thread::Id +Thread::id() +{ + return m_id; +} + +bool +Thread::threadingAvailable() +{ + return true; +} + +DWORD +Thread::staticRun(LPVOID arg) +{ + Thread *thread = static_cast<Thread *>(arg); +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: " << (void *)GetCurrentThreadId() << ": Running thread " << thread->m_id << " for thread object " << thread << endl; +#endif + thread->run(); + return 0; +} + +Mutex::Mutex() : + m_locked(false) +{ + m_mutex = CreateMutex(NULL, FALSE, NULL); +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised mutex " << &m_mutex << endl; +#endif +} + +Mutex::~Mutex() +{ +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying mutex " << &m_mutex << endl; +#endif + CloseHandle(m_mutex); +} + +void +Mutex::lock() +{ + if (m_locked) { + cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl; + } +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Want to lock mutex " << &m_mutex << endl; +#endif + WaitForSingleObject(m_mutex, INFINITE); + m_locked = true; +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Locked mutex " << &m_mutex << endl; +#endif +} + +void +Mutex::unlock() +{ +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Unlocking mutex " << &m_mutex << endl; +#endif + m_locked = false; + ReleaseMutex(m_mutex); +} + +bool +Mutex::trylock() +{ + DWORD result = WaitForSingleObject(m_mutex, 0); + if (result == WAIT_TIMEOUT || result == WAIT_FAILED) { +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Mutex " << &m_mutex << " unavailable" << endl; +#endif + return false; + } else { + m_locked = true; +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Locked mutex " << &m_mutex << " (from trylock)" << endl; +#endif + return true; + } +} + +Condition::Condition(string name) : + m_name(name), + m_locked(false) +{ + m_mutex = CreateMutex(NULL, FALSE, NULL); + m_condition = CreateEvent(NULL, FALSE, FALSE, NULL); +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised condition " << &m_condition << " \"" << m_name << "\"" << endl; +#endif +} + +Condition::~Condition() +{ +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying condition " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + if (m_locked) ReleaseMutex(m_mutex); + CloseHandle(m_condition); + CloseHandle(m_mutex); +} + +void +Condition::lock() +{ + if (m_locked) { +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Already locked " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + return; + } +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Want to lock " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + WaitForSingleObject(m_mutex, INFINITE); + m_locked = true; +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Locked " << &m_condition << " \"" << m_name << "\"" << endl; +#endif +} + +void +Condition::unlock() +{ + if (!m_locked) { +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Not locked " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + return; + } +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Unlocking " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + m_locked = false; + ReleaseMutex(m_mutex); +} + +void +Condition::wait(int us) +{ + if (!m_locked) lock(); + + if (us == 0) { + +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Waiting on " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + SignalObjectAndWait(m_mutex, m_condition, INFINITE, FALSE); + WaitForSingleObject(m_mutex, INFINITE); + + } else { + + DWORD ms = us / 1000; + if (us > 0 && ms == 0) ms = 1; + +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Timed waiting on " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + SignalObjectAndWait(m_mutex, m_condition, ms, FALSE); + WaitForSingleObject(m_mutex, INFINITE); + } + + ReleaseMutex(m_mutex); + +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Wait done on " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + m_locked = false; +} + +void +Condition::signal() +{ +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Signalling " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + SetEvent(m_condition); +} + +#else /* !_WIN32 */ + + +Thread::Thread() : + m_id(0), + m_extant(false) +{ +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Created thread object " << this << endl; +#endif +} + +Thread::~Thread() +{ +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Destroying thread object " << this << ", id " << m_id << endl; +#endif + if (m_extant) { + pthread_join(m_id, 0); + } +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Destroyed thread object " << this << endl; +#endif +} + +void +Thread::start() +{ + if (pthread_create(&m_id, 0, staticRun, this)) { + cerr << "ERROR: thread creation failed" << endl; + exit(1); + } else { +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Created thread " << m_id << " for thread object " << this << endl; +#endif + m_extant = true; + } +} + +void +Thread::wait() +{ + if (m_extant) { +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Waiting on thread " << m_id << " for thread object " << this << endl; +#endif + pthread_join(m_id, 0); +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: Waited on thread " << m_id << " for thread object " << this << endl; +#endif + m_extant = false; + } +} + +Thread::Id +Thread::id() +{ + return m_id; +} + +bool +Thread::threadingAvailable() +{ + return true; +} + +void * +Thread::staticRun(void *arg) +{ + Thread *thread = static_cast<Thread *>(arg); +#ifdef DEBUG_THREAD + cerr << "THREAD DEBUG: " << (void *)pthread_self() << ": Running thread " << thread->m_id << " for thread object " << thread << endl; +#endif + thread->run(); + return 0; +} + +Mutex::Mutex() : + m_locked(false) +{ + pthread_mutex_init(&m_mutex, 0); +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Initialised mutex " << &m_mutex << endl; +#endif +} + +Mutex::~Mutex() +{ +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Destroying mutex " << &m_mutex << endl; +#endif + pthread_mutex_destroy(&m_mutex); +} + +void +Mutex::lock() +{ + if (m_locked) { + cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl; + } +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Want to lock mutex " << &m_mutex << endl; +#endif + pthread_mutex_lock(&m_mutex); + m_locked = true; +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Locked mutex " << &m_mutex << endl; +#endif +} + +void +Mutex::unlock() +{ +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Unlocking mutex " << &m_mutex << endl; +#endif + m_locked = false; + pthread_mutex_unlock(&m_mutex); +} + +bool +Mutex::trylock() +{ + if (pthread_mutex_trylock(&m_mutex)) { +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Mutex " << &m_mutex << " unavailable" << endl; +#endif + return false; + } else { + m_locked = true; +#ifdef DEBUG_MUTEX + cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Locked mutex " << &m_mutex << " (from trylock)" << endl; +#endif + return true; + } +} + +Condition::Condition(string name) : + m_locked(false), + m_name(name) +{ + pthread_mutex_init(&m_mutex, 0); + pthread_cond_init(&m_condition, 0); +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Initialised condition " << &m_condition << " \"" << m_name << "\"" << endl; +#endif +} + +Condition::~Condition() +{ +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Destroying condition " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + if (m_locked) pthread_mutex_unlock(&m_mutex); + pthread_cond_destroy(&m_condition); + pthread_mutex_destroy(&m_mutex); +} + +void +Condition::lock() +{ + if (m_locked) { +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Already locked " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + return; + } +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Want to lock " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + pthread_mutex_lock(&m_mutex); + m_locked = true; +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Locked " << &m_condition << " \"" << m_name << "\"" << endl; +#endif +} + +void +Condition::unlock() +{ + if (!m_locked) { +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Not locked " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + return; + } +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Unlocking " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + m_locked = false; + pthread_mutex_unlock(&m_mutex); +} + +void +Condition::wait(int us) +{ + if (!m_locked) lock(); + + if (us == 0) { + +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Waiting on " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + pthread_cond_wait(&m_condition, &m_mutex); + + } else { + + struct timeval now; + gettimeofday(&now, 0); + + now.tv_usec += us; + while (now.tv_usec > 1000000) { + now.tv_usec -= 1000000; + ++now.tv_sec; + } + + struct timespec timeout; + timeout.tv_sec = now.tv_sec; + timeout.tv_nsec = now.tv_usec * 1000; + +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Timed waiting on " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + pthread_cond_timedwait(&m_condition, &m_mutex, &timeout); + } + + pthread_mutex_unlock(&m_mutex); + +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Wait done on " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + m_locked = false; +} + +void +Condition::signal() +{ +#ifdef DEBUG_CONDITION + cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Signalling " << &m_condition << " \"" << m_name << "\"" << endl; +#endif + pthread_cond_signal(&m_condition); +} + +#endif /* !_WIN32 */ + +MutexLocker::MutexLocker(Mutex *mutex) : + m_mutex(mutex) +{ + if (m_mutex) { + m_mutex->lock(); + } +} + +MutexLocker::~MutexLocker() +{ + if (m_mutex) { + m_mutex->unlock(); + } +} + +} + diff --git a/libs/rubberband/1.0/src/Thread.h b/libs/rubberband/1.0/src/Thread.h new file mode 100644 index 0000000000..dc37f6dd45 --- /dev/null +++ b/libs/rubberband/1.0/src/Thread.h @@ -0,0 +1,131 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_THREAD_H_ +#define _RUBBERBAND_THREAD_H_ + +#ifdef _WIN32 +#include <windows.h> +#else /* !_WIN32 */ +#include <pthread.h> +#endif /* !_WIN32 */ + +#include <string> + +namespace RubberBand +{ + +class Thread +{ +public: +#ifdef _WIN32 + typedef HANDLE Id; +#else + typedef pthread_t Id; +#endif + + Thread(); + virtual ~Thread(); + + Id id(); + + void start(); + void wait(); + + static bool threadingAvailable(); + +protected: + virtual void run() = 0; + +private: +#ifdef _WIN32 + HANDLE m_id; + bool m_extant; + static DWORD WINAPI staticRun(LPVOID lpParam); +#else + pthread_t m_id; + bool m_extant; + static void *staticRun(void *); +#endif +}; + +class Mutex +{ +public: + Mutex(); + ~Mutex(); + + void lock(); + void unlock(); + bool trylock(); + +private: +#ifdef _WIN32 + HANDLE m_mutex; + bool m_locked; +#else + pthread_mutex_t m_mutex; + bool m_locked; +#endif +}; + +class MutexLocker +{ +public: + MutexLocker(Mutex *); + ~MutexLocker(); + +private: + Mutex *m_mutex; +}; + +class Condition +{ +public: + Condition(std::string name); + ~Condition(); + + // To wait on a condition, either simply call wait(), or call + // lock() and then wait() (perhaps testing some state in between). + // To signal a condition, call signal(). + + // Although any thread may signal on a given condition, only one + // thread should ever wait on any given condition object -- + // otherwise there will be a race conditions in the logic that + // avoids the thread code having to track whether the condition's + // mutex is locked or not. If that is your requirement, this + // Condition wrapper is not for you. + void lock(); + void unlock(); + void wait(int us = 0); + + void signal(); + +private: +#ifdef _WIN32 + HANDLE m_mutex; + bool m_locked; + HANDLE m_condition; + std::string m_name; +#else + pthread_mutex_t m_mutex; + bool m_locked; + pthread_cond_t m_condition; + std::string m_name; +#endif +}; + +} + +#endif diff --git a/libs/rubberband/1.0/src/Window.h b/libs/rubberband/1.0/src/Window.h new file mode 100644 index 0000000000..305daa7332 --- /dev/null +++ b/libs/rubberband/1.0/src/Window.h @@ -0,0 +1,165 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_WINDOW_H_ +#define _RUBBERBAND_WINDOW_H_ + +#include <cmath> +#include <iostream> +#include <map> + +namespace RubberBand { + +enum WindowType { + RectangularWindow, + BartlettWindow, + HammingWindow, + HanningWindow, + BlackmanWindow, + GaussianWindow, + ParzenWindow, + NuttallWindow, + BlackmanHarrisWindow +}; + +template <typename T> +class Window +{ +public: + /** + * Construct a windower of the given type. + */ + Window(WindowType type, size_t size) : m_type(type), m_size(size) { encache(); } + Window(const Window &w) : m_type(w.m_type), m_size(w.m_size) { encache(); } + Window &operator=(const Window &w) { + if (&w == this) return *this; + m_type = w.m_type; + m_size = w.m_size; + encache(); + return *this; + } + virtual ~Window() { delete[] m_cache; } + + void cut(T *src) const { cut(src, src); } + void cut(T *src, T *dst) const { + for (size_t i = 0; i < m_size; ++i) dst[i] = src[i] * m_cache[i]; + } + + T getArea() { return m_area; } + T getValue(size_t i) { return m_cache[i]; } + + WindowType getType() const { return m_type; } + size_t getSize() const { return m_size; } + +protected: + WindowType m_type; + size_t m_size; + T *m_cache; + T m_area; + + void encache(); + void cosinewin(T *, T, T, T, T); +}; + +template <typename T> +void Window<T>::encache() +{ + int n = int(m_size); + T *mult = new T[n]; + int i; + for (i = 0; i < n; ++i) mult[i] = 1.0; + + switch (m_type) { + + case RectangularWindow: + for (i = 0; i < n; ++i) { + mult[i] *= 0.5; + } + break; + + case BartlettWindow: + for (i = 0; i < n/2; ++i) { + mult[i] *= (i / T(n/2)); + mult[i + n/2] *= (1.0 - (i / T(n/2))); + } + break; + + case HammingWindow: + cosinewin(mult, 0.54, 0.46, 0.0, 0.0); + break; + + case HanningWindow: + cosinewin(mult, 0.50, 0.50, 0.0, 0.0); + break; + + case BlackmanWindow: + cosinewin(mult, 0.42, 0.50, 0.08, 0.0); + break; + + case GaussianWindow: + for (i = 0; i < n; ++i) { + mult[i] *= pow(2, - pow((i - (n-1)/2.0) / ((n-1)/2.0 / 3), 2)); + } + break; + + case ParzenWindow: + { + int N = n-1; + for (i = 0; i < N/4; ++i) { + T m = 2 * pow(1.0 - (T(N)/2 - i) / (T(N)/2), 3); + mult[i] *= m; + mult[N-i] *= m; + } + for (i = N/4; i <= N/2; ++i) { + int wn = i - N/2; + T m = 1.0 - 6 * pow(wn / (T(N)/2), 2) * (1.0 - abs(wn) / (T(N)/2)); + mult[i] *= m; + mult[N-i] *= m; + } + break; + } + + case NuttallWindow: + cosinewin(mult, 0.3635819, 0.4891775, 0.1365995, 0.0106411); + break; + + case BlackmanHarrisWindow: + cosinewin(mult, 0.35875, 0.48829, 0.14128, 0.01168); + break; + } + + m_cache = mult; + + m_area = 0; + for (int i = 0; i < n; ++i) { + m_area += m_cache[i]; + } + m_area /= n; +} + +template <typename T> +void Window<T>::cosinewin(T *mult, T a0, T a1, T a2, T a3) +{ + int n = int(m_size); + for (int i = 0; i < n; ++i) { + mult[i] *= (a0 + - a1 * cos(2 * M_PI * i / n) + + a2 * cos(4 * M_PI * i / n) + - a3 * cos(6 * M_PI * i / n)); + } +} + +} + +#endif diff --git a/libs/rubberband/1.0/src/ladspa/RubberBandPitchShifter.cpp b/libs/rubberband/1.0/src/ladspa/RubberBandPitchShifter.cpp new file mode 100644 index 0000000000..c0b2813c79 --- /dev/null +++ b/libs/rubberband/1.0/src/ladspa/RubberBandPitchShifter.cpp @@ -0,0 +1,408 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "RubberBandPitchShifter.h" + +#include "RubberBandStretcher.h" + +#include <iostream> +#include <cmath> + +using namespace RubberBand; + +const char *const +RubberBandPitchShifter::portNamesMono[PortCountMono] = +{ + "_latency", + "Cents", + "Semitones", + "Octaves", + "Crispness", + "Input", + "Output" +}; + +const char *const +RubberBandPitchShifter::portNamesStereo[PortCountStereo] = +{ + "_latency", + "Cents", + "Semitones", + "Octaves", + "Crispness", + "Input L", + "Output L", + "Input R", + "Output R" +}; + +const LADSPA_PortDescriptor +RubberBandPitchShifter::portsMono[PortCountMono] = +{ + LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO +}; + +const LADSPA_PortDescriptor +RubberBandPitchShifter::portsStereo[PortCountStereo] = +{ + LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL, + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, + LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO +}; + +const LADSPA_PortRangeHint +RubberBandPitchShifter::hintsMono[PortCountMono] = +{ + { 0, 0, 0 }, + { LADSPA_HINT_DEFAULT_0 | + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE, + -100.0, 100.0 }, + { LADSPA_HINT_DEFAULT_0 | + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_INTEGER, + -12.0, 12.0 }, + { LADSPA_HINT_DEFAULT_0 | + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_INTEGER, + -4.0, 4.0 }, + { LADSPA_HINT_DEFAULT_MAXIMUM | + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_INTEGER, + 0.0, 3.0 }, + { 0, 0, 0 }, + { 0, 0, 0 } +}; + +const LADSPA_PortRangeHint +RubberBandPitchShifter::hintsStereo[PortCountStereo] = +{ + { 0, 0, 0 }, + { LADSPA_HINT_DEFAULT_0 | + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE, + -100.0, 100.0 }, + { LADSPA_HINT_DEFAULT_0 | + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_INTEGER, + -12.0, 12.0 }, + { LADSPA_HINT_DEFAULT_0 | + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_INTEGER, + -4.0, 4.0 }, + { LADSPA_HINT_DEFAULT_MAXIMUM | + LADSPA_HINT_BOUNDED_BELOW | + LADSPA_HINT_BOUNDED_ABOVE | + LADSPA_HINT_INTEGER, + 0.0, 3.0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 } +}; + +const LADSPA_Properties +RubberBandPitchShifter::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE; + +const LADSPA_Descriptor +RubberBandPitchShifter::ladspaDescriptorMono = +{ + 2979, // "Unique" ID + "rubberband-pitchshifter-mono", // Label + properties, + "Rubber Band Mono Pitch Shifter", // Name + "Chris Cannam", + "GPL", + PortCountMono, + portsMono, + portNamesMono, + hintsMono, + 0, // Implementation data + instantiate, + connectPort, + activate, + run, + 0, // Run adding + 0, // Set run adding gain + deactivate, + cleanup +}; + +const LADSPA_Descriptor +RubberBandPitchShifter::ladspaDescriptorStereo = +{ + 9792, // "Unique" ID + "rubberband-pitchshifter-stereo", // Label + properties, + "Rubber Band Stereo Pitch Shifter", // Name + "Chris Cannam", + "GPL", + PortCountStereo, + portsStereo, + portNamesStereo, + hintsStereo, + 0, // Implementation data + instantiate, + connectPort, + activate, + run, + 0, // Run adding + 0, // Set run adding gain + deactivate, + cleanup +}; + +const LADSPA_Descriptor * +RubberBandPitchShifter::getDescriptor(unsigned long index) +{ + if (index == 0) return &ladspaDescriptorMono; + if (index == 1) return &ladspaDescriptorStereo; + else return 0; +} + +RubberBandPitchShifter::RubberBandPitchShifter(int sampleRate, size_t channels) : + m_latency(0), + m_cents(0), + m_semitones(0), + m_octaves(0), + m_crispness(0), + m_ratio(1.0), + m_prevRatio(1.0), + m_currentCrispness(-1), + m_extraLatency(8192), //!!! this should be at least the maximum possible displacement from linear at input rates, divided by the pitch scale factor. It could be very large + m_stretcher(new RubberBandStretcher + (sampleRate, channels, + RubberBandStretcher::OptionProcessRealTime)), + m_sampleRate(sampleRate), + m_channels(channels) +{ + for (size_t c = 0; c < m_channels; ++c) { + m_input[c] = 0; + m_output[c] = 0; + //!!! size must be at least max process size plus m_extraLatency: + m_outputBuffer[c] = new RingBuffer<float>(8092); //!!! + m_outputBuffer[c]->zero(m_extraLatency); + //!!! size must be at least max process size: + m_scratch[c] = new float[16384];//!!! + } +} + +RubberBandPitchShifter::~RubberBandPitchShifter() +{ + delete m_stretcher; + for (size_t c = 0; c < m_channels; ++c) { + delete m_outputBuffer[c]; + delete[] m_scratch[c]; + } +} + +LADSPA_Handle +RubberBandPitchShifter::instantiate(const LADSPA_Descriptor *desc, unsigned long rate) +{ + if (desc->PortCount == ladspaDescriptorMono.PortCount) { + return new RubberBandPitchShifter(rate, 1); + } else if (desc->PortCount == ladspaDescriptorStereo.PortCount) { + return new RubberBandPitchShifter(rate, 2); + } + return 0; +} + +void +RubberBandPitchShifter::connectPort(LADSPA_Handle handle, + unsigned long port, LADSPA_Data *location) +{ + RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle; + + float **ports[PortCountStereo] = { + &shifter->m_latency, + &shifter->m_cents, + &shifter->m_semitones, + &shifter->m_octaves, + &shifter->m_crispness, + &shifter->m_input[0], + &shifter->m_output[0], + &shifter->m_input[1], + &shifter->m_output[1] + }; + + *ports[port] = (float *)location; +} + +void +RubberBandPitchShifter::activate(LADSPA_Handle handle) +{ + RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle; + shifter->updateRatio(); + shifter->m_prevRatio = shifter->m_ratio; + shifter->m_stretcher->reset(); + shifter->m_stretcher->setPitchScale(shifter->m_ratio); +} + +void +RubberBandPitchShifter::run(LADSPA_Handle handle, unsigned long samples) +{ + RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle; + shifter->runImpl(samples); +} + +void +RubberBandPitchShifter::updateRatio() +{ + double oct = *m_octaves; + oct += *m_semitones / 12; + oct += *m_cents / 1200; + m_ratio = pow(2.0, oct); +} + +void +RubberBandPitchShifter::updateCrispness() +{ + if (!m_crispness) return; + + int c = lrintf(*m_crispness); + if (c == m_currentCrispness) return; + if (c < 0 || c > 3) return; + RubberBandStretcher *s = m_stretcher; + + switch (c) { + case 0: + s->setPhaseOption(RubberBandStretcher::OptionPhaseIndependent); + s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth); + break; + case 1: + s->setPhaseOption(RubberBandStretcher::OptionPhaseAdaptive); + s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth); + break; + case 2: + s->setPhaseOption(RubberBandStretcher::OptionPhaseAdaptive); + s->setTransientsOption(RubberBandStretcher::OptionTransientsMixed); + break; + case 3: + s->setPhaseOption(RubberBandStretcher::OptionPhaseAdaptive); + s->setTransientsOption(RubberBandStretcher::OptionTransientsCrisp); + break; + } + + m_currentCrispness = c; +} + +void +RubberBandPitchShifter::runImpl(unsigned long insamples) +{ +// std::cerr << "RubberBandPitchShifter::runImpl(" << insamples << ")" << std::endl; + + updateRatio(); + if (m_ratio != m_prevRatio) { + m_stretcher->setPitchScale(m_ratio); + m_prevRatio = m_ratio; + } + + if (m_latency) { + *m_latency = m_stretcher->getLatency() + m_extraLatency; +// std::cerr << "latency = " << *m_latency << std::endl; + } + + updateCrispness(); + + int samples = insamples; + int processed = 0; + size_t outTotal = 0; + + float *ptrs[2]; + + // We have to break up the input into chunks like this because + // insamples could be arbitrarily large + + while (processed < samples) { + + //!!! size_t: + int toCauseProcessing = m_stretcher->getSamplesRequired(); +// std::cout << "to-cause: " << toCauseProcessing << ", remain = " << samples - processed; + int inchunk = std::min(samples - processed, toCauseProcessing); + for (size_t c = 0; c < m_channels; ++c) { + ptrs[c] = &(m_input[c][processed]); + } + m_stretcher->process(ptrs, inchunk, false); + processed += inchunk; + + int avail = m_stretcher->available(); + int writable = m_outputBuffer[0]->getWriteSpace(); + int outchunk = std::min(avail, writable); + size_t actual = m_stretcher->retrieve(m_scratch, outchunk); + outTotal += actual; + +// std::cout << ", avail: " << avail << ", outchunk = " << outchunk; +// if (actual != outchunk) std::cout << " (" << actual << ")"; +// std::cout << std::endl; + + outchunk = actual; + + for (size_t c = 0; c < m_channels; ++c) { + if (int(m_outputBuffer[c]->getWriteSpace()) < outchunk) { + std::cerr << "RubberBandPitchShifter::runImpl: buffer overrun: chunk = " << outchunk << ", space = " << m_outputBuffer[c]->getWriteSpace() << std::endl; + } + m_outputBuffer[c]->write(m_scratch[c], outchunk); + } + } + +// std::cout << "processed = " << processed << " in, " << outTotal << " out" << ", fill = " << m_outputBuffer[0]->getReadSpace() << " of " << m_outputBuffer[0]->getSize() << std::endl; + + for (size_t c = 0; c < m_channels; ++c) { + int avail = m_outputBuffer[c]->getReadSpace(); +// std::cout << "avail: " << avail << std::endl; + if (avail < samples && c == 0) { + std::cerr << "RubberBandPitchShifter::runImpl: buffer underrun: required = " << samples << ", available = " << avail << std::endl; + } + int chunk = std::min(avail, samples); +// std::cout << "out chunk: " << chunk << std::endl; + m_outputBuffer[c]->read(m_output[c], chunk); + } + + static int minr = -1; + int avail = m_outputBuffer[0]->getReadSpace(); + if (minr == -1 || (avail >= 0 && avail < minr)) { + std::cerr << "RubberBandPitchShifter::runImpl: new min remaining " << avail << " from " << minr << std::endl; + minr = avail; + } +} + +void +RubberBandPitchShifter::deactivate(LADSPA_Handle handle) +{ + activate(handle); // both functions just reset the plugin +} + +void +RubberBandPitchShifter::cleanup(LADSPA_Handle handle) +{ + delete (RubberBandPitchShifter *)handle; +} + diff --git a/libs/rubberband/1.0/src/ladspa/RubberBandPitchShifter.h b/libs/rubberband/1.0/src/ladspa/RubberBandPitchShifter.h new file mode 100644 index 0000000000..3adfb61bc1 --- /dev/null +++ b/libs/rubberband/1.0/src/ladspa/RubberBandPitchShifter.h @@ -0,0 +1,95 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_PITCH_SHIFTER_H_ +#define _RUBBERBAND_PITCH_SHIFTER_H_ + +#include "ladspa.h" + +#include "RingBuffer.h" + +namespace RubberBand { +class RubberBandStretcher; +} + +class RubberBandPitchShifter +{ +public: + static const LADSPA_Descriptor *getDescriptor(unsigned long index); + +protected: + RubberBandPitchShifter(int sampleRate, size_t channels); + ~RubberBandPitchShifter(); + + enum { + LatencyPort = 0, + OctavesPort = 1, + SemitonesPort = 2, + CentsPort = 3, + CrispnessPort = 4, + InputPort1 = 5, + OutputPort1 = 6, + PortCountMono = OutputPort1 + 1, + InputPort2 = 7, + OutputPort2 = 8, + PortCountStereo = OutputPort2 + 1 + }; + + static const char *const portNamesMono[PortCountMono]; + static const LADSPA_PortDescriptor portsMono[PortCountMono]; + static const LADSPA_PortRangeHint hintsMono[PortCountMono]; + + static const char *const portNamesStereo[PortCountStereo]; + static const LADSPA_PortDescriptor portsStereo[PortCountStereo]; + static const LADSPA_PortRangeHint hintsStereo[PortCountStereo]; + + static const LADSPA_Properties properties; + + static const LADSPA_Descriptor ladspaDescriptorMono; + static const LADSPA_Descriptor ladspaDescriptorStereo; + + static LADSPA_Handle instantiate(const LADSPA_Descriptor *, unsigned long); + static void connectPort(LADSPA_Handle, unsigned long, LADSPA_Data *); + static void activate(LADSPA_Handle); + static void run(LADSPA_Handle, unsigned long); + static void deactivate(LADSPA_Handle); + static void cleanup(LADSPA_Handle); + + void runImpl(unsigned long); + void updateRatio(); + void updateCrispness(); + + float *m_input[2]; + float *m_output[2]; + float *m_latency; + float *m_cents; + float *m_semitones; + float *m_octaves; + float *m_crispness; + double m_ratio; + double m_prevRatio; + int m_currentCrispness; + + size_t m_extraLatency; + + RubberBand::RubberBandStretcher *m_stretcher; + RubberBand::RingBuffer<float> *m_outputBuffer[2]; + float *m_scratch[2]; + + int m_sampleRate; + size_t m_channels; +}; + + +#endif diff --git a/libs/rubberband/1.0/src/ladspa/ladspa-rubberband.cat b/libs/rubberband/1.0/src/ladspa/ladspa-rubberband.cat new file mode 100644 index 0000000000..438e9a3909 --- /dev/null +++ b/libs/rubberband/1.0/src/ladspa/ladspa-rubberband.cat @@ -0,0 +1,2 @@ +ladspa:ladspa-rubberband:rubberband-pitchshifter-mono::Frequency > Pitch shifters +ladspa:ladspa-rubberband:rubberband-pitchshifter-stereo::Frequency > Pitch shifters diff --git a/libs/rubberband/1.0/src/ladspa/libmain.cpp b/libs/rubberband/1.0/src/ladspa/libmain.cpp new file mode 100644 index 0000000000..afc7ac0709 --- /dev/null +++ b/libs/rubberband/1.0/src/ladspa/libmain.cpp @@ -0,0 +1,26 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "RubberBandPitchShifter.h" + +#include <stdio.h> + +extern "C" { + +const LADSPA_Descriptor *ladspa_descriptor(unsigned long index) +{ + return RubberBandPitchShifter::getDescriptor(index); +} + +} diff --git a/libs/rubberband/1.0/src/main.cpp b/libs/rubberband/1.0/src/main.cpp new file mode 100644 index 0000000000..c4f9259ae6 --- /dev/null +++ b/libs/rubberband/1.0/src/main.cpp @@ -0,0 +1,475 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "RubberBandStretcher.h" + +#include <iostream> +#include <sndfile.h> +#include <cmath> +#include <sys/time.h> +#include <time.h> +#include "sysutils.h" + +#include <getopt.h> + +// for import and export of FFTW wisdom +#include <fftw3.h> + +using namespace std; +using namespace RubberBand; + +#ifdef _WIN32 +using RubberBand::gettimeofday; +using RubberBand::usleep; +#endif + +int main(int argc, char **argv) +{ + int c; + + double ratio = 1.0; + double pitchshift = 1.0; + double frequencyshift = 1.0; + int debug = 0; + bool realtime = false; + bool precise = false; + int threading = 0; + bool peaklock = true; + bool longwin = false; + bool shortwin = false; + bool softening = true; + int crispness = -1; + bool help = false; + bool quiet = false; + + bool haveRatio = false; + + enum { + NoTransients, + BandLimitedTransients, + Transients + } transients = Transients; + + float fthresh0 = -1.f; + float fthresh1 = -1.f; + float fthresh2 = -1.f; + + while (1) { + int optionIndex = 0; + + static struct option longOpts[] = { + { "help", 0, 0, 'h' }, + { "time", 1, 0, 't' }, + { "tempo", 1, 0, 'T' }, + { "pitch", 1, 0, 'p' }, + { "frequency", 1, 0, 'f' }, + { "crisp", 1, 0, 'c' }, + { "crispness", 1, 0, 'c' }, + { "debug", 1, 0, 'd' }, + { "realtime", 0, 0, 'R' }, + { "precise", 0, 0, 'P' }, + { "no-threads", 0, 0, '0' }, + { "no-transients", 0, 0, '1' }, + { "no-peaklock", 0, 0, '2' }, + { "window-long", 0, 0, '3' }, + { "window-short", 0, 0, '4' }, + { "thresh0", 1, 0, '5' }, + { "thresh1", 1, 0, '6' }, + { "thresh2", 1, 0, '7' }, + { "bl-transients", 0, 0, '8' }, + { "no-softening", 0, 0, '9' }, + { "threads", 0, 0, '@' }, + { "quiet", 0, 0, 'q' }, + { 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "t:p:d:RPc:f:qh", longOpts, &optionIndex); + if (c == -1) break; + + switch (c) { + case 'h': help = true; break; + case 't': ratio *= atof(optarg); haveRatio = true; break; + case 'T': { double m = atof(optarg); if (m != 0.0) ratio /= m; }; haveRatio = true; break; + case 'p': pitchshift = atof(optarg); haveRatio = true; break; + case 'f': frequencyshift = atof(optarg); haveRatio = true; break; + case 'd': debug = atoi(optarg); break; + case 'R': realtime = true; break; + case 'P': precise = true; break; + case '0': threading = 1; break; + case '@': threading = 2; break; + case '1': transients = NoTransients; break; + case '2': peaklock = false; break; + case '3': longwin = true; break; + case '4': shortwin = true; break; + case '5': fthresh0 = atof(optarg); break; + case '6': fthresh1 = atof(optarg); break; + case '7': fthresh2 = atof(optarg); break; + case '8': transients = BandLimitedTransients; break; + case '9': softening = false; break; + case 'c': crispness = atoi(optarg); break; + case 'q': quiet = true; break; + default: help = true; break; + } + } + + if (help || !haveRatio || optind + 2 != argc) { + cerr << endl; + cerr << "Rubber Band" << endl; + cerr << "An audio time-stretching and pitch-shifting library and utility program." << endl; + cerr << "Copyright 2007 Chris Cannam. Distributed under the GNU General Public License." << endl; + cerr << endl; + cerr << " Usage: " << argv[0] << " [options] <infile.wav> <outfile.wav>" << endl; + cerr << endl; + cerr << "You must specify at least one of the following time and pitch ratio options." << endl; + cerr << endl; + cerr << " -t<X>, --time <X> Stretch to X times original duration, or" << endl; + cerr << " -T<X>, --tempo <X> Change tempo by multiple X (equivalent to --time 1/X)" << endl; + cerr << endl; + cerr << " -p<X>, --pitch <X> Raise pitch by X semitones, or" << endl; + cerr << " -f<X>, --frequency <X> Change frequency by multiple X" << endl; + cerr << endl; + cerr << "The following option provides a simple way to adjust the sound. See below" << endl; + cerr << "for more details." << endl; + cerr << endl; + cerr << " -c<N>, --crisp <N> Crispness (N = 0,1,2,3,4,5); default 4 (see below)" << endl; + cerr << endl; + cerr << "The remaining options fine-tune the processing mode and stretch algorithm." << endl; + cerr << "These are mostly included for test purposes; the default settings and standard" << endl; + cerr << "crispness parameter are intended to provide the best sounding set of options" << endl; + cerr << "for most situations." << endl; + cerr << endl; + cerr << " -P, --precise Aim for minimal time distortion (implied by -R)" << endl; + cerr << " -R, --realtime Select realtime mode (implies -P --no-threads)" << endl; + cerr << " --no-threads No extra threads regardless of CPU and channel count" << endl; + cerr << " --threads Assume multi-CPU even if only one CPU is identified" << endl; + cerr << " --no-transients Disable phase resynchronisation at transients" << endl; + cerr << " --bl-transients Band-limit phase resync to extreme frequencies" << endl; + cerr << " --no-peaklock Disable phase locking to peak frequencies" << endl; + cerr << " --no-softening Disable large-ratio softening of phase locking" << endl; + cerr << " --window-long Use longer processing window (actual size may vary)" << endl; + cerr << " --window-short Use shorter processing window" << endl; + cerr << " --thresh<N> <F> Set internal freq threshold N (N = 0,1,2) to F Hz" << endl; + cerr << endl; + cerr << " -d<N>, --debug <N> Select debug level (N = 0,1,2,3); default 0, full 3" << endl; + cerr << " (N.B. debug level 3 includes audible ticks in output)" << endl; + cerr << " -q, --quiet Suppress progress output" << endl; + cerr << endl; + cerr << " -h, --help Show this help" << endl; + cerr << endl; + cerr << "\"Crispness\" levels:" << endl; + cerr << " -c 0 equivalent to --no-transients --no-peaklock --window-long" << endl; + cerr << " -c 1 equivalent to --no-transients --no-peaklock" << endl; + cerr << " -c 2 equivalent to --no-transients" << endl; + cerr << " -c 3 equivalent to --bl-transients" << endl; + cerr << " -c 4 default processing options" << endl; + cerr << " -c 5 equivalent to --no-peaklock --window-short (may be suitable for drums)" << endl; + cerr << endl; + return 2; + } + + switch (crispness) { + case -1: crispness = 4; break; + case 0: transients = NoTransients; peaklock = false; longwin = true; shortwin = false; break; + case 1: transients = NoTransients; peaklock = false; longwin = false; shortwin = false; break; + case 2: transients = NoTransients; peaklock = true; longwin = false; shortwin = false; break; + case 3: transients = BandLimitedTransients; peaklock = true; longwin = false; shortwin = false; break; + case 4: transients = Transients; peaklock = true; longwin = false; shortwin = false; break; + case 5: transients = Transients; peaklock = false; longwin = false; shortwin = true; break; + }; + + if (!quiet) { + cerr << "Using crispness level: " << crispness << " ("; + switch (crispness) { + case 0: cerr << "Mushy"; break; + case 1: cerr << "Smooth"; break; + case 2: cerr << "Balanced multitimbral mixture"; break; + case 3: cerr << "Unpitched percussion with stable notes"; break; + case 4: cerr << "Crisp monophonic instrumental"; break; + case 5: cerr << "Unpitched solo percussion"; break; + } + cerr << ")" << endl; + } + + char *fileName = strdup(argv[optind++]); + char *fileNameOut = strdup(argv[optind++]); + + SNDFILE *sndfile; + SNDFILE *sndfileOut; + SF_INFO sfinfo; + SF_INFO sfinfoOut; + memset(&sfinfo, 0, sizeof(SF_INFO)); + + sndfile = sf_open(fileName, SFM_READ, &sfinfo); + if (!sndfile) { + cerr << "ERROR: Failed to open input file \"" << fileName << "\": " + << sf_strerror(sndfile) << endl; + return 1; + } + + sfinfoOut.channels = sfinfo.channels; + sfinfoOut.format = sfinfo.format; + sfinfoOut.frames = int(sfinfo.frames * ratio + 0.1); + sfinfoOut.samplerate = sfinfo.samplerate; + sfinfoOut.sections = sfinfo.sections; + sfinfoOut.seekable = sfinfo.seekable; + + sndfileOut = sf_open(fileNameOut, SFM_WRITE, &sfinfoOut) ; + if (!sndfileOut) { + cerr << "ERROR: Failed to open output file \"" << fileName << "\" for writing: " + << sf_strerror(sndfile) << endl; + return 1; + } + + int ibs = 1024; + size_t channels = sfinfo.channels; + + RubberBandStretcher::Options options = 0; + if (realtime) options |= RubberBandStretcher::OptionProcessRealTime; + if (precise) options |= RubberBandStretcher::OptionStretchPrecise; + if (!peaklock) options |= RubberBandStretcher::OptionPhaseIndependent; + if (!softening) options |= RubberBandStretcher::OptionPhasePeakLocked; + if (longwin) options |= RubberBandStretcher::OptionWindowLong; + if (shortwin) options |= RubberBandStretcher::OptionWindowShort; + + switch (threading) { + case 0: + options |= RubberBandStretcher::OptionThreadingAuto; + break; + case 1: + options |= RubberBandStretcher::OptionThreadingNever; + break; + case 2: + options |= RubberBandStretcher::OptionThreadingAlways; + break; + } + + switch (transients) { + case NoTransients: + options |= RubberBandStretcher::OptionTransientsSmooth; + break; + case BandLimitedTransients: + options |= RubberBandStretcher::OptionTransientsMixed; + break; + case Transients: + options |= RubberBandStretcher::OptionTransientsCrisp; + break; + } + + if (pitchshift != 1.0) { + frequencyshift *= pow(2.0, pitchshift / 12); + } + +#ifdef _WIN32 + RubberBand:: +#endif + timeval tv; + (void)gettimeofday(&tv, 0); + + RubberBandStretcher::setDefaultDebugLevel(debug); + + RubberBandStretcher ts(sfinfo.samplerate, channels, options, + ratio, frequencyshift); + + ts.setExpectedInputDuration(sfinfo.frames); + + float *fbuf = new float[channels * ibs]; + float **ibuf = new float *[channels]; + for (size_t i = 0; i < channels; ++i) ibuf[i] = new float[ibs]; + + int frame = 0; + int percent = 0; + + sf_seek(sndfile, 0, SEEK_SET); + + if (!realtime) { + + if (!quiet) { + cerr << "Pass 1: Studying..." << endl; + } + + while (frame < sfinfo.frames) { + + int count = -1; + + if ((count = sf_readf_float(sndfile, fbuf, ibs)) <= 0) break; + + for (size_t c = 0; c < channels; ++c) { + for (int i = 0; i < count; ++i) { + float value = fbuf[i * channels + c]; + ibuf[c][i] = value; + } + } + + bool final = (frame + ibs >= sfinfo.frames); + + ts.study(ibuf, count, final); + + int p = int((double(frame) * 100.0) / sfinfo.frames); + if (p > percent || frame == 0) { + percent = p; + if (!quiet) { + cerr << "\r" << percent << "% "; + } + } + + frame += ibs; + } + + if (!quiet) { + cerr << "\rCalculating profile..." << endl; + } + + sf_seek(sndfile, 0, SEEK_SET); + } + + frame = 0; + percent = 0; + + size_t countIn = 0, countOut = 0; + + while (frame < sfinfo.frames) { + + int count = -1; + + if ((count = sf_readf_float(sndfile, fbuf, ibs)) < 0) break; + + countIn += count; + + for (size_t c = 0; c < channels; ++c) { + for (int i = 0; i < count; ++i) { + float value = fbuf[i * channels + c]; + ibuf[c][i] = value; + } + } + + bool final = (frame + ibs >= sfinfo.frames); + + ts.process(ibuf, count, final); + + int avail = ts.available(); + if (debug > 1) cerr << "available = " << avail << endl; + + if (avail > 0) { + float **obf = new float *[channels]; + for (size_t i = 0; i < channels; ++i) { + obf[i] = new float[avail]; + } + ts.retrieve(obf, avail); + countOut += avail; + float *fobf = new float[channels * avail]; + for (size_t c = 0; c < channels; ++c) { + for (int i = 0; i < avail; ++i) { + float value = obf[c][i]; + if (value > 1.f) value = 1.f; + if (value < -1.f) value = -1.f; + fobf[i * channels + c] = value; + } + } +// cout << "fobf mean: "; +// double d = 0; +// for (int i = 0; i < avail; ++i) { +// d += fobf[i]; +// } +// d /= avail; +// cout << d << endl; + sf_writef_float(sndfileOut, fobf, avail); + delete[] fobf; + for (size_t i = 0; i < channels; ++i) { + delete[] obf[i]; + } + delete[] obf; + } + + if (frame == 0 && !realtime && !quiet) { + cerr << "Pass 2: Processing..." << endl; + } + + int p = int((double(frame) * 100.0) / sfinfo.frames); + if (p > percent || frame == 0) { + percent = p; + if (!quiet) { + cerr << "\r" << percent << "% "; + } + } + + frame += ibs; + } + + if (!quiet) { + cerr << "\r " << endl; + } + int avail; + + while ((avail = ts.available()) >= 0) { + + if (debug > 1) { + cerr << "(completing) available = " << avail << endl; + } + + if (avail > 0) { + float **obf = new float *[channels]; + for (size_t i = 0; i < channels; ++i) { + obf[i] = new float[avail]; + } + ts.retrieve(obf, avail); + countOut += avail; + float *fobf = new float[channels * avail]; + for (size_t c = 0; c < channels; ++c) { + for (int i = 0; i < avail; ++i) { + float value = obf[c][i]; + if (value > 1.f) value = 1.f; + if (value < -1.f) value = -1.f; + fobf[i * channels + c] = value; + } + } + + sf_writef_float(sndfileOut, fobf, avail); + delete[] fobf; + for (size_t i = 0; i < channels; ++i) { + delete[] obf[i]; + } + delete[] obf; + } else { + usleep(10000); + } + } + + sf_close(sndfile); + sf_close(sndfileOut); + + if (!quiet) { + + cerr << "in: " << countIn << ", out: " << countOut << ", ratio: " << float(countOut)/float(countIn) << ", ideal output: " << lrint(countIn * ratio) << ", error: " << abs(lrint(countIn * ratio) - int(countOut)) << endl; + +#ifdef _WIN32 + RubberBand:: +#endif + timeval etv; + (void)gettimeofday(&etv, 0); + + etv.tv_sec -= tv.tv_sec; + if (etv.tv_usec < tv.tv_usec) { + etv.tv_usec += 1000000; + etv.tv_sec -= 1; + } + etv.tv_usec -= tv.tv_usec; + + double sec = double(etv.tv_sec) + (double(etv.tv_usec) / 1000000.0); + cerr << "elapsed time: " << sec << " sec, in frames/sec: " << countIn/sec << ", out frames/sec: " << countOut/sec << endl; + } + + return 0; +} + + diff --git a/libs/rubberband/1.0/src/sysutils.cpp b/libs/rubberband/1.0/src/sysutils.cpp new file mode 100644 index 0000000000..fc4a17b3e7 --- /dev/null +++ b/libs/rubberband/1.0/src/sysutils.cpp @@ -0,0 +1,106 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "sysutils.h" + +#ifdef _WIN32 +#include <windows.h> +#else /* !_WIN32 */ +#ifdef __APPLE__ +#include <sys/sysctl.h> +#else /* !__APPLE__, !_WIN32 */ +#include <stdio.h> +#include <string.h> +#endif /* !__APPLE__, !_WIN32 */ +#endif /* !_WIN32 */ + +#include <iostream> + +namespace RubberBand { + +bool +system_is_multiprocessor() +{ + static bool tested = false, mp = false; + + if (tested) return mp; + int count = 0; + +#ifdef _WIN32 + + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + count = sysinfo.dwNumberOfProcessors; + +#else /* !_WIN32 */ +#ifdef __APPLE__ + + size_t sz = sizeof(count); + if (sysctlbyname("hw.ncpu", &count, &sz, NULL, 0)) { + mp = false; + } else { + mp = (count > 1); + } + +#else /* !__APPLE__, !_WIN32 */ + + //... + + FILE *cpuinfo = fopen("/proc/cpuinfo", "r"); + if (!cpuinfo) return false; + + char buf[256]; + while (!feof(cpuinfo)) { + fgets(buf, 256, cpuinfo); + if (!strncmp(buf, "processor", 9)) { + ++count; + } + if (count > 1) break; + } + + fclose(cpuinfo); + +#endif /* !__APPLE__, !_WIN32 */ +#endif /* !_WIN32 */ + + mp = (count > 1); + tested = true; + return mp; +} + +#ifdef _WIN32 + +void gettimeofday(struct timeval *tv, void *tz) +{ + union { + long long ns100; + FILETIME ft; + } now; + + ::GetSystemTimeAsFileTime(&now.ft); + tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL); + tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL); +} + +void usleep(unsigned long usec) +{ + ::Sleep(usec == 0 ? 0 : usec < 1000 ? 1 : usec / 1000); +} + +#endif + +} + + + diff --git a/libs/rubberband/1.0/src/sysutils.h b/libs/rubberband/1.0/src/sysutils.h new file mode 100644 index 0000000000..b9dd23e79c --- /dev/null +++ b/libs/rubberband/1.0/src/sysutils.h @@ -0,0 +1,30 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_SYSINFO_H_ +#define _RUBBERBAND_SYSINFO_H_ + +namespace RubberBand { + +extern bool system_is_multiprocessor(); + +#ifdef _WIN32 +struct timeval { long tv_sec; long tv_usec; }; +void gettimeofday(struct timeval *p, void *tz); +void usleep(unsigned long); +#endif + +} + +#endif diff --git a/libs/rubberband/1.0/src/vamp/RubberBandVampPlugin.cpp b/libs/rubberband/1.0/src/vamp/RubberBandVampPlugin.cpp new file mode 100644 index 0000000000..1e9227fac0 --- /dev/null +++ b/libs/rubberband/1.0/src/vamp/RubberBandVampPlugin.cpp @@ -0,0 +1,647 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include "RubberBandVampPlugin.h" + +#include "StretchCalculator.h" + +#include <cmath> + +using std::string; +using std::vector; +using std::cerr; +using std::endl; + +class RubberBandVampPlugin::Impl +{ +public: + size_t m_stepSize; + size_t m_blockSize; + size_t m_sampleRate; + + float m_timeRatio; + float m_pitchRatio; + + bool m_realtime; + bool m_elasticTiming; + int m_transientMode; + bool m_phaseIndependent; + int m_windowLength; + + RubberBand::RubberBandStretcher *m_stretcher; + + int m_incrementsOutput; + int m_aggregateIncrementsOutput; + int m_divergenceOutput; + int m_phaseResetDfOutput; + int m_smoothedPhaseResetDfOutput; + int m_phaseResetPointsOutput; + int m_timeSyncPointsOutput; + + size_t m_counter; + size_t m_accumulatedIncrement; + + float **m_outputDump; + + FeatureSet processOffline(const float *const *inputBuffers, + Vamp::RealTime timestamp); + + FeatureSet getRemainingFeaturesOffline(); + + FeatureSet processRealTime(const float *const *inputBuffers, + Vamp::RealTime timestamp); + + FeatureSet getRemainingFeaturesRealTime(); + + FeatureSet createFeatures(size_t inputIncrement, + std::vector<int> &outputIncrements, + std::vector<float> &phaseResetDf, + std::vector<int> &exactPoints, + std::vector<float> &smoothedDf, + size_t baseCount, + bool includeFinal); +}; + + +RubberBandVampPlugin::RubberBandVampPlugin(float inputSampleRate) : + Plugin(inputSampleRate) +{ + m_d = new Impl(); + m_d->m_stepSize = 0; + m_d->m_timeRatio = 1.f; + m_d->m_pitchRatio = 1.f; + m_d->m_realtime = false; + m_d->m_elasticTiming = true; + m_d->m_transientMode = 0; + m_d->m_phaseIndependent = false; + m_d->m_windowLength = 0; + m_d->m_stretcher = 0; + m_d->m_sampleRate = lrintf(m_inputSampleRate); +} + +RubberBandVampPlugin::~RubberBandVampPlugin() +{ + if (m_d->m_outputDump) { + for (size_t i = 0; i < m_d->m_stretcher->getChannelCount(); ++i) { + delete[] m_d->m_outputDump[i]; + } + delete[] m_d->m_outputDump; + } + delete m_d->m_stretcher; + delete m_d; +} + +string +RubberBandVampPlugin::getIdentifier() const +{ + return "rubberband"; +} + +string +RubberBandVampPlugin::getName() const +{ + return "Rubber Band Timestretch Analysis"; +} + +string +RubberBandVampPlugin::getDescription() const +{ + return "Carry out analysis phases of time stretcher process"; +} + +string +RubberBandVampPlugin::getMaker() const +{ + return "Rubber Band"; ///!!! +} + +int +RubberBandVampPlugin::getPluginVersion() const +{ + return 1; +} + +string +RubberBandVampPlugin::getCopyright() const +{ + return "";//!!! +} + +RubberBandVampPlugin::OutputList +RubberBandVampPlugin::getOutputDescriptors() const +{ + OutputList list; + + size_t rate = 0; + if (m_d->m_stretcher) { + rate = lrintf(m_inputSampleRate / m_d->m_stretcher->getInputIncrement()); + } + + OutputDescriptor d; + d.identifier = "increments"; + d.name = "Output Increments"; + d.description = "Output time increment for each input step"; + d.unit = "samples"; + d.hasFixedBinCount = true; + d.binCount = 1; + d.hasKnownExtents = false; + d.isQuantized = true; + d.quantizeStep = 1.0; + d.sampleType = OutputDescriptor::VariableSampleRate; + d.sampleRate = rate; + m_d->m_incrementsOutput = list.size(); + list.push_back(d); + + d.identifier = "aggregate_increments"; + d.name = "Accumulated Output Increments"; + d.description = "Accumulated output time increments"; + d.sampleRate = 0; + m_d->m_aggregateIncrementsOutput = list.size(); + list.push_back(d); + + d.identifier = "divergence"; + d.name = "Divergence from Linear"; + d.description = "Difference between actual output time and the output time for a theoretical linear stretch"; + d.isQuantized = false; + d.sampleRate = 0; + m_d->m_divergenceOutput = list.size(); + list.push_back(d); + + d.identifier = "phaseresetdf"; + d.name = "Phase Reset Detection Function"; + d.description = "Curve whose peaks are used to identify transients for phase reset points"; + d.unit = ""; + d.sampleRate = rate; + m_d->m_phaseResetDfOutput = list.size(); + list.push_back(d); + + d.identifier = "smoothedphaseresetdf"; + d.name = "Smoothed Phase Reset Detection Function"; + d.description = "Phase reset curve smoothed for peak picking"; + d.unit = ""; + m_d->m_smoothedPhaseResetDfOutput = list.size(); + list.push_back(d); + + d.identifier = "phaseresetpoints"; + d.name = "Phase Reset Points"; + d.description = "Points estimated as transients at which phase reset occurs"; + d.unit = ""; + d.hasFixedBinCount = true; + d.binCount = 0; + d.hasKnownExtents = false; + d.isQuantized = false; + d.sampleRate = 0; + m_d->m_phaseResetPointsOutput = list.size(); + list.push_back(d); + + d.identifier = "timesyncpoints"; + d.name = "Time Sync Points"; + d.description = "Salient points which stretcher aims to place with strictly correct timing"; + d.unit = ""; + d.hasFixedBinCount = true; + d.binCount = 0; + d.hasKnownExtents = false; + d.isQuantized = false; + d.sampleRate = 0; + m_d->m_timeSyncPointsOutput = list.size(); + list.push_back(d); + + return list; +} + +RubberBandVampPlugin::ParameterList +RubberBandVampPlugin::getParameterDescriptors() const +{ + ParameterList list; + + ParameterDescriptor d; + d.identifier = "timeratio"; + d.name = "Time Ratio"; + d.description = "Ratio to modify overall duration by"; + d.unit = "%"; + d.minValue = 1; + d.maxValue = 500; + d.defaultValue = 100; + d.isQuantized = false; + list.push_back(d); + + d.identifier = "pitchratio"; + d.name = "Pitch Scale Ratio"; + d.description = "Frequency ratio to modify pitch by"; + d.unit = "%"; + d.minValue = 1; + d.maxValue = 500; + d.defaultValue = 100; + d.isQuantized = false; + list.push_back(d); + + d.identifier = "mode"; + d.name = "Processing Mode"; + d.description = ""; //!!! + d.unit = ""; + d.minValue = 0; + d.maxValue = 1; + d.defaultValue = 0; + d.isQuantized = true; + d.quantizeStep = 1; + d.valueNames.clear(); + d.valueNames.push_back("Offline"); + d.valueNames.push_back("Real Time"); + list.push_back(d); + + d.identifier = "stretchtype"; + d.name = "Stretch Flexibility"; + d.description = ""; //!!! + d.unit = ""; + d.minValue = 0; + d.maxValue = 1; + d.defaultValue = 0; + d.isQuantized = true; + d.quantizeStep = 1; + d.valueNames.clear(); + d.valueNames.push_back("Elastic"); + d.valueNames.push_back("Precise"); + list.push_back(d); + + d.identifier = "transientmode"; + d.name = "Transient Handling"; + d.description = ""; //!!! + d.unit = ""; + d.minValue = 0; + d.maxValue = 2; + d.defaultValue = 0; + d.isQuantized = true; + d.quantizeStep = 1; + d.valueNames.clear(); + d.valueNames.push_back("Mixed"); + d.valueNames.push_back("Smooth"); + d.valueNames.push_back("Crisp"); + list.push_back(d); + + d.identifier = "phasemode"; + d.name = "Phase Handling"; + d.description = ""; //!!! + d.unit = ""; + d.minValue = 0; + d.maxValue = 1; + d.defaultValue = 0; + d.isQuantized = true; + d.quantizeStep = 1; + d.valueNames.clear(); + d.valueNames.push_back("Peak Locked"); + d.valueNames.push_back("Independent"); + list.push_back(d); + + d.identifier = "windowmode"; + d.name = "Window Length"; + d.description = ""; //!!! + d.unit = ""; + d.minValue = 0; + d.maxValue = 2; + d.defaultValue = 0; + d.isQuantized = true; + d.quantizeStep = 1; + d.valueNames.clear(); + d.valueNames.push_back("Standard"); + d.valueNames.push_back("Short"); + d.valueNames.push_back("Long"); + list.push_back(d); + + return list; +} + +float +RubberBandVampPlugin::getParameter(std::string id) const +{ + if (id == "timeratio") return m_d->m_timeRatio * 100.f; + if (id == "pitchratio") return m_d->m_pitchRatio * 100.f; + if (id == "mode") return m_d->m_realtime ? 1 : 0; + if (id == "stretchtype") return m_d->m_elasticTiming ? 0 : 1; + if (id == "transientmode") return m_d->m_transientMode; + if (id == "phasemode") return m_d->m_phaseIndependent ? 1 : 0; + if (id == "windowmode") return m_d->m_windowLength; + return 0.f; +} + +void +RubberBandVampPlugin::setParameter(std::string id, float value) +{ + if (id == "timeratio") { + m_d->m_timeRatio = value / 100; + } else if (id == "pitchratio") { + m_d->m_pitchRatio = value / 100; + } else { + bool set = (value > 0.5); + if (id == "mode") m_d->m_realtime = set; + else if (id == "stretchtype") m_d->m_elasticTiming = !set; + else if (id == "transientmode") m_d->m_transientMode = int(value + 0.5); + else if (id == "phasemode") m_d->m_phaseIndependent = set; + else if (id == "windowmode") m_d->m_windowLength = int(value + 0.5); + } +} + +bool +RubberBandVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + m_d->m_stepSize = std::min(stepSize, blockSize); + m_d->m_blockSize = stepSize; + + RubberBand::RubberBandStretcher::Options options = 0; + + if (m_d->m_realtime) + options |= RubberBand::RubberBandStretcher::OptionProcessRealTime; + else options |= RubberBand::RubberBandStretcher::OptionProcessOffline; + + if (m_d->m_elasticTiming) + options |= RubberBand::RubberBandStretcher::OptionStretchElastic; + else options |= RubberBand::RubberBandStretcher::OptionStretchPrecise; + + if (m_d->m_transientMode == 0) + options |= RubberBand::RubberBandStretcher::OptionTransientsMixed; + else if (m_d->m_transientMode == 1) + options |= RubberBand::RubberBandStretcher::OptionTransientsSmooth; + else options |= RubberBand::RubberBandStretcher::OptionTransientsCrisp; + + if (m_d->m_phaseIndependent) + options |= RubberBand::RubberBandStretcher::OptionPhaseIndependent; + else options |= RubberBand::RubberBandStretcher::OptionPhasePeakLocked; + + if (m_d->m_windowLength == 0) + options |= RubberBand::RubberBandStretcher::OptionWindowStandard; + else if (m_d->m_windowLength == 1) + options |= RubberBand::RubberBandStretcher::OptionWindowShort; + else options |= RubberBand::RubberBandStretcher::OptionWindowLong; + + delete m_d->m_stretcher; + m_d->m_stretcher = new RubberBand::RubberBandStretcher + (m_d->m_sampleRate, channels, options); + m_d->m_stretcher->setDebugLevel(1); + m_d->m_stretcher->setTimeRatio(m_d->m_timeRatio); + m_d->m_stretcher->setPitchScale(m_d->m_pitchRatio); + + m_d->m_counter = 0; + m_d->m_accumulatedIncrement = 0; + + m_d->m_outputDump = 0; + + return true; +} + +void +RubberBandVampPlugin::reset() +{ +// delete m_stretcher; //!!! or just if (m_stretcher) m_stretcher->reset(); +// m_stretcher = new RubberBand::RubberBandStretcher(lrintf(m_inputSampleRate), channels); + if (m_d->m_stretcher) m_d->m_stretcher->reset(); +} + +RubberBandVampPlugin::FeatureSet +RubberBandVampPlugin::process(const float *const *inputBuffers, + Vamp::RealTime timestamp) +{ + if (m_d->m_realtime) { + return m_d->processRealTime(inputBuffers, timestamp); + } else { + return m_d->processOffline(inputBuffers, timestamp); + } +} + +RubberBandVampPlugin::FeatureSet +RubberBandVampPlugin::getRemainingFeatures() +{ + if (m_d->m_realtime) { + return m_d->getRemainingFeaturesRealTime(); + } else { + return m_d->getRemainingFeaturesOffline(); + } +} + +RubberBandVampPlugin::FeatureSet +RubberBandVampPlugin::Impl::processOffline(const float *const *inputBuffers, + Vamp::RealTime timestamp) +{ + if (!m_stretcher) { + cerr << "ERROR: RubberBandVampPlugin::processOffline: " + << "RubberBandVampPlugin has not been initialised" + << endl; + return FeatureSet(); + } + + m_stretcher->study(inputBuffers, m_blockSize, false); + return FeatureSet(); +} + +RubberBandVampPlugin::FeatureSet +RubberBandVampPlugin::Impl::getRemainingFeaturesOffline() +{ + m_stretcher->study(0, 0, true); + + m_stretcher->calculateStretch(); + + int rate = m_sampleRate; + + RubberBand::StretchCalculator sc(rate, + m_stretcher->getInputIncrement(), + true); + + size_t inputIncrement = m_stretcher->getInputIncrement(); + std::vector<int> outputIncrements = m_stretcher->getOutputIncrements(); + std::vector<float> phaseResetDf = m_stretcher->getPhaseResetCurve(); + std::vector<int> peaks = m_stretcher->getExactTimePoints(); + std::vector<float> smoothedDf = sc.smoothDF(phaseResetDf); + + FeatureSet features = createFeatures + (inputIncrement, outputIncrements, phaseResetDf, peaks, smoothedDf, + 0, true); + + return features; +} + +RubberBandVampPlugin::FeatureSet +RubberBandVampPlugin::Impl::processRealTime(const float *const *inputBuffers, + Vamp::RealTime timestamp) +{ + // This function is not in any way a real-time function (i.e. it + // has no requirement to be RT safe); it simply operates the + // stretcher in RT mode. + + if (!m_stretcher) { + cerr << "ERROR: RubberBandVampPlugin::processRealTime: " + << "RubberBandVampPlugin has not been initialised" + << endl; + return FeatureSet(); + } + + m_stretcher->process(inputBuffers, m_blockSize, false); + + size_t inputIncrement = m_stretcher->getInputIncrement(); + std::vector<int> outputIncrements = m_stretcher->getOutputIncrements(); + std::vector<float> phaseResetDf = m_stretcher->getPhaseResetCurve(); + std::vector<float> smoothedDf; // not meaningful in RT mode + std::vector<int> dummyPoints; + FeatureSet features = createFeatures + (inputIncrement, outputIncrements, phaseResetDf, dummyPoints, smoothedDf, + m_counter, false); + m_counter += outputIncrements.size(); + + int available = 0; + while ((available = m_stretcher->available()) > 0) { + if (!m_outputDump) { + m_outputDump = new float *[m_stretcher->getChannelCount()]; + for (size_t i = 0; i < m_stretcher->getChannelCount(); ++i) { + m_outputDump[i] = new float[m_blockSize]; + } + } + m_stretcher->retrieve(m_outputDump, + std::min(int(m_blockSize), available)); + } + + return features; +} + +RubberBandVampPlugin::FeatureSet +RubberBandVampPlugin::Impl::getRemainingFeaturesRealTime() +{ + return FeatureSet(); +} + +RubberBandVampPlugin::FeatureSet +RubberBandVampPlugin::Impl::createFeatures(size_t inputIncrement, + std::vector<int> &outputIncrements, + std::vector<float> &phaseResetDf, + std::vector<int> &exactPoints, + std::vector<float> &smoothedDf, + size_t baseCount, + bool includeFinal) +{ + size_t actual = m_accumulatedIncrement; + + double overallRatio = m_timeRatio * m_pitchRatio; + + char label[200]; + + FeatureSet features; + + int rate = m_sampleRate; + + size_t epi = 0; + + for (size_t i = 0; i < outputIncrements.size(); ++i) { + + size_t frame = (baseCount + i) * inputIncrement; + + int oi = outputIncrements[i]; + bool hard = false; + bool soft = false; + + if (oi < 0) { + oi = -oi; + hard = true; + } + + if (epi < exactPoints.size() && int(i) == exactPoints[epi]) { + soft = true; + ++epi; + } + + double linear = (frame * overallRatio); + + Vamp::RealTime t = Vamp::RealTime::frame2RealTime(frame, rate); + + Feature feature; + feature.hasTimestamp = true; + feature.timestamp = t; + feature.values.push_back(oi); + feature.label = Vamp::RealTime::frame2RealTime(oi, rate).toText(); + features[m_incrementsOutput].push_back(feature); + + feature.values.clear(); + feature.values.push_back(actual); + feature.label = Vamp::RealTime::frame2RealTime(actual, rate).toText(); + features[m_aggregateIncrementsOutput].push_back(feature); + + feature.values.clear(); + feature.values.push_back(actual - linear); + + sprintf(label, "expected %ld, actual %ld, difference %ld (%s ms)", + long(linear), long(actual), long(actual - linear), + // frame2RealTime expects an integer frame number, + // hence our multiplication factor + (Vamp::RealTime::frame2RealTime + (lrintf((actual - linear) * 1000), rate) / 1000) + .toText().c_str()); + feature.label = label; + + features[m_divergenceOutput].push_back(feature); + actual += oi; + + char buf[30]; + + if (i < phaseResetDf.size()) { + feature.values.clear(); + feature.values.push_back(phaseResetDf[i]); + sprintf(buf, "%d", baseCount + i); + feature.label = buf; + features[m_phaseResetDfOutput].push_back(feature); + } + + if (i < smoothedDf.size()) { + feature.values.clear(); + feature.values.push_back(smoothedDf[i]); + features[m_smoothedPhaseResetDfOutput].push_back(feature); + } + + if (hard) { + feature.values.clear(); + feature.label = "Phase Reset"; + features[m_phaseResetPointsOutput].push_back(feature); + } + + if (hard || soft) { + feature.values.clear(); + feature.label = "Time Sync"; + features[m_timeSyncPointsOutput].push_back(feature); + } + } + + if (includeFinal) { + Vamp::RealTime t = Vamp::RealTime::frame2RealTime + (inputIncrement * (baseCount + outputIncrements.size()), rate); + Feature feature; + feature.hasTimestamp = true; + feature.timestamp = t; + feature.label = Vamp::RealTime::frame2RealTime(actual, rate).toText(); + feature.values.clear(); + feature.values.push_back(actual); + features[m_aggregateIncrementsOutput].push_back(feature); + + float linear = ((baseCount + outputIncrements.size()) + * inputIncrement * overallRatio); + feature.values.clear(); + feature.values.push_back(actual - linear); + feature.label = // see earlier comment + (Vamp::RealTime::frame2RealTime //!!! update this as earlier label + (lrintf((actual - linear) * 1000), rate) / 1000) + .toText(); + features[m_divergenceOutput].push_back(feature); + } + + m_accumulatedIncrement = actual; + + return features; +} + diff --git a/libs/rubberband/1.0/src/vamp/RubberBandVampPlugin.h b/libs/rubberband/1.0/src/vamp/RubberBandVampPlugin.h new file mode 100644 index 0000000000..f850a282da --- /dev/null +++ b/libs/rubberband/1.0/src/vamp/RubberBandVampPlugin.h @@ -0,0 +1,56 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RUBBERBAND_VAMP_PLUGIN_H_ +#define _RUBBERBAND_VAMP_PLUGIN_H_ + +#include <vamp-sdk/Plugin.h> + +#include "RubberBandStretcher.h" + +class RubberBandVampPlugin : public Vamp::Plugin +{ +public: + RubberBandVampPlugin(float inputSampleRate); + virtual ~RubberBandVampPlugin(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + void reset(); + + InputDomain getInputDomain() const { return TimeDomain; } + + std::string getIdentifier() const; + std::string getName() const; + std::string getDescription() const; + std::string getMaker() const; + int getPluginVersion() const; + std::string getCopyright() const; + + ParameterList getParameterDescriptors() const; + float getParameter(std::string id) const; + void setParameter(std::string id, float value); + + OutputList getOutputDescriptors() const; + + FeatureSet process(const float *const *inputBuffers, + Vamp::RealTime timestamp); + + FeatureSet getRemainingFeatures(); + +protected: + class Impl; + Impl *m_d; +}; + +#endif diff --git a/libs/rubberband/1.0/src/vamp/libmain.cpp b/libs/rubberband/1.0/src/vamp/libmain.cpp new file mode 100644 index 0000000000..a535c2008c --- /dev/null +++ b/libs/rubberband/1.0/src/vamp/libmain.cpp @@ -0,0 +1,32 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rubber Band + An audio time-stretching and pitch-shifting library. + Copyright 2007 Chris Cannam. + + 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. See the file + COPYING included with this distribution for more information. +*/ + +#include <vamp/vamp.h> +#include <vamp-sdk/PluginAdapter.h> + +#include "RubberBandVampPlugin.h" + +static Vamp::PluginAdapter<RubberBandVampPlugin> rubberBandAdapter; + +const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version, + unsigned int index) +{ + if (version < 1) return 0; + + switch (index) { + case 0: return rubberBandAdapter.getDescriptor(); + default: return 0; + } +} + diff --git a/libs/rubberband/1.0/src/vamp/vamp-rubberband.cat b/libs/rubberband/1.0/src/vamp/vamp-rubberband.cat new file mode 100644 index 0000000000..d1ef2caba8 --- /dev/null +++ b/libs/rubberband/1.0/src/vamp/vamp-rubberband.cat @@ -0,0 +1 @@ +vamp:vamp-rubberband:rubberband::Time > Timestretch Analysis |