remove VAMP and Rubberband from source tree

This commit is contained in:
Paul Davis
2014-01-12 15:39:58 -05:00
parent 4b3feefa55
commit 83c0720645
96 changed files with 26 additions and 22089 deletions

View File

@@ -288,10 +288,9 @@ def configure(conf):
autowaf.check_pkg(conf, 'libcurl', uselib_store='CURL',
atleast_version='7.0.0')
# we don't try to detect this, since its part of our source tree
conf.define('HAVE_RUBBERBAND', 1) # controls whether we think we have it
conf.define('USE_RUBBERBAND', 1) # controls whether we actually use it
# controls whether we actually use it in preference to soundtouch
# Note: as of 2104, soundtouch (WSOLA) has been out-of-use for years.
conf.define('USE_RUBBERBAND', 1)
conf.define('CURRENT_SESSION_FILE_VERSION', CURRENT_SESSION_FILE_VERSION)
@@ -338,17 +337,15 @@ def build(bld):
obj.target = 'ardour'
obj.uselib = ['GLIBMM','GTHREAD','AUBIO','SIGCPP','XML','UUID',
'SNDFILE','SAMPLERATE','LRDF','AUDIOUNITS',
'OSX','BOOST','CURL','DL','TAGLIB']
obj.use = ['libpbd','libmidipp','libevoral', 'libvampplugin',
'OSX','BOOST','CURL','DL','TAGLIB','VAMPSDK','VAMPHOSTSDK','RUBBERBAND']
obj.use = ['libpbd','libmidipp','libevoral',
'libaudiographer',
'libtimecode',
]
if bld.is_defined('USE_EXTERNAL_LIBS'):
obj.uselib.extend(['RUBBERBAND', 'VAMPSDK', 'LIBLTC',
'VAMPHOSTSDK'])
obj.uselib.extend(['VAMPSDK', 'LIBLTC'])
else:
obj.use.extend(['librubberband', 'libvamphost'
'libltc_includes', 'libltc'])
obj.use.extend(['librubberband', 'libltc_includes', 'libltc'])
obj.vnum = LIBARDOUR_LIB_VERSION
obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
@@ -413,21 +410,18 @@ def build(bld):
testcommon.source = ['test/testrunner.cc', 'test/test_needing_session.cc',
'test/test_common.cc', 'test/dummy_lxvst.cc', 'test/audio_region_test.cc', 'test/test_util.cc']
testcommon.uselib = ['CPPUNIT','SIGCPP','GLIBMM','GTHREAD',
'SAMPLERATE','XML','LRDF','COREAUDIO','TAGLIB']
'SAMPLERATE','XML','LRDF','COREAUDIO','TAGLIB','VAMPSDK','VAMPHOSTSDK','RUBBERBAND']
testcommon.use = ['libpbd','libmidipp','libevoral',
'libvampplugin','libaudiographer','ardour']
'libaudiographer','ardour']
if bld.is_defined('USE_EXTERNAL_LIBS'):
testcommon.uselib.extend(['RUBBERBAND', 'LIBLTC', 'VAMPSDK',
'VAMPHOSTSDK'])
testcommon.uselib.extend(['LIBLTC',])
else:
testcommon.use.extend(['libltc', 'librubberband', 'libvamphost'])
testcommon.use.extend(['libltc', 'librubberband'])
testcommon.defines = [
'DATA_DIR="' + os.path.normpath(bld.env['DATADIR']) + '"',
'CONFIG_DIR="' + os.path.normpath(bld.env['SYSCONFDIR']) + '"',
'LOCALEDIR="' + os.path.join(
os.path.normpath(bld.env['DATADIR']), 'locale') + '"',
'VAMP_DIR="' + os.path.join(
os.path.normpath(bld.env['LIBDIR']), 'ardour3', 'vamp') + '"'
]
testcommon.name = 'testcommon'
@@ -508,8 +502,6 @@ def build(bld):
'CONFIG_DIR="' + os.path.normpath(bld.env['SYSCONFDIR']) + '"',
'LOCALEDIR="' + os.path.join(
os.path.normpath(bld.env['DATADIR']), 'locale') + '"',
'VAMP_DIR="' + os.path.join(
os.path.normpath(bld.env['LIBDIR']), 'ardour3', 'vamp') + '"'
]
if bld.env['FPU_OPTIMIZATION']:
session_load_tester.source += [ 'sse_functions_xmm.cc' ]
@@ -543,8 +535,6 @@ def build(bld):
'CONFIG_DIR="' + os.path.normpath(bld.env['SYSCONFDIR']) + '"',
'LOCALEDIR="' + os.path.join(
os.path.normpath(bld.env['DATADIR']), 'locale') + '"',
'VAMP_DIR="' + os.path.join(
os.path.normpath(bld.env['LIBDIR']), 'ardour3', 'vamp') + '"'
]
if bld.env['FPU_OPTIMIZATION']:
profilingobj.source += [ 'sse_functions_xmm.cc' ]
@@ -559,14 +549,13 @@ def create_ardour_test_program(bld, includes, name, target, sources):
testobj.includes = includes + ['test', '../pbd', '..']
testobj.source = sources
testobj.uselib = ['CPPUNIT','SIGCPP','GLIBMM','GTHREAD',
'SAMPLERATE','XML','LRDF','COREAUDIO','TAGLIB']
testobj.use = ['libpbd','libmidipp','libevoral','libvampplugin',
'SAMPLERATE','XML','LRDF','COREAUDIO','TAGLIB','VAMPSDK','VAMPHOSTSDK','RUBBERBAND']
testobj.use = ['libpbd','libmidipp','libevoral',
'libaudiographer','ardour','testcommon']
if bld.is_defined('USE_EXTERNAL_LIBS'):
testobj.uselib.extend(['RUBBERBAND', 'LIBLTC', 'VAMPSDK',
'VAMPHOSTSDK'])
testobj.uselib.extend(['LIBLTC'])
else:
testobj.use.extend(['libltc', 'librubberband', 'libvamphost'])
testobj.use.extend(['libltc'])
testobj.name = name
testobj.target = target
@@ -578,8 +567,6 @@ def create_ardour_test_program(bld, includes, name, target, sources):
'CONFIG_DIR="' + os.path.normpath(bld.env['SYSCONFDIR']) + '"',
'LOCALEDIR="' + os.path.join(
os.path.normpath(bld.env['DATADIR']), 'locale') + '"',
'VAMP_DIR="' + os.path.join(
os.path.normpath(bld.env['LIBDIR']), 'ardour3', 'vamp') + '"'
]
def shutdown():

View File

@@ -1,280 +0,0 @@
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

View File

@@ -1,189 +0,0 @@
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

View File

@@ -1,158 +0,0 @@
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.

View File

@@ -1,38 +0,0 @@
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])

View File

@@ -1,144 +0,0 @@
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

View File

@@ -1,28 +0,0 @@
#!/bin/sh
#
# this script copies the relevant files from $1 into this
# working copy of the repository, adds new files and
# prints a list of mods for SConscript
#
from=$1
#strip=`dirname $1`
strip=$1
echo "Looking for copies in $from ... will strip $strip"
for file in `find $from \( -name \*.cpp -o -name \*.h -o -name \*.c \)`
do
src=$file
copy=`echo $file | sed "s?$strip/??"`
echo "Look for $copy"
if [ -f $copy ] ; then
cp $src $copy
echo "copy $copy"
else
echo "ADD $copy"
cp $src $copy
svn add $copy
fi
done

View File

@@ -1,10 +0,0 @@
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}

View File

@@ -1,563 +0,0 @@
/* -*- 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-2008 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_
#define RUBBERBAND_VERSION "1.3.0-gpl"
#define RUBBERBAND_API_MAJOR_VERSION 2
#define RUBBERBAND_API_MINOR_VERSION 0
#include <cstddef>
#include <vector>
/**
* @mainpage RubberBand
*
* The Rubber Band API is contained in the single class
* RubberBand::RubberBandStretcher.
*
* Threading notes for real-time applications:
*
* Multiple instances of RubberBandStretcher may be created and used
* in separate threads concurrently. However, for any single instance
* of RubberBandStretcher, you may not call process() more than once
* concurrently, and you may not change the time or pitch ratio while
* a process() call is being executed (if the stretcher was created in
* "real-time mode"; in "offline mode" you can't change the ratios
* during use anyway).
*
* So you can run process() in its own thread if you like, but if you
* want to change ratios dynamically from a different thread, you will
* need some form of mutex in your code. Changing the time or pitch
* ratio is real-time safe except in extreme circumstances, so for
* most applications that may change these dynamically it probably
* makes most sense to do so from the same thread as calls process(),
* even if that is a real-time thread.
*/
namespace RubberBand
{
class RubberBandStretcher
{
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 OptionPhaseLaminar - Adjust phases when stretching in
* such a way as to try to retain the continuity of phase
* relationships between adjacent frequency bins whose phases
* are behaving in similar ways. This, the default setting,
* should give good results in most situations.
*
* \li \c OptionPhaseIndependent - Adjust the phase in each
* frequency bin independently from its neighbours. This
* usually results in a slightly 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.
*
* 7. Flags prefixed \c OptionFormant control the handling of
* formant shape (spectral envelope) when pitch-shifting. These
* options may be changed at any time.
*
* \li \c OptionFormantShifted - Apply no special formant
* processing. The spectral envelope will be pitch shifted as
* normal.
*
* \li \c OptionFormantPreserved - Preserve the spectral
* envelope of the unshifted signal. This permits shifting the
* note frequency without so substantially affecting the
* perceived pitch profile of the voice or instrument.
*
* 8. Flags prefixed \c OptionPitch control the method used for
* pitch shifting. These options may be changed at any time.
* They are only effective in realtime mode; in offline mode, the
* pitch-shift method is fixed.
*
* \li \c OptionPitchHighSpeed - Use a method with a CPU cost
* that is relatively moderate and predictable. This may
* sound less clear than OptionPitchHighQuality, especially
* for large pitch shifts.
* \li \c OptionPitchHighQuality - Use the highest quality
* method for pitch shifting. This method has a CPU cost
* approximately proportional to the required frequency shift.
* \li \c OptionPitchHighConsistency - Use the method that gives
* greatest consistency when used to create small variations in
* pitch around the 1.0-ratio level. Unlike the previous two
* options, this avoids discontinuities when moving across the
* 1.0 pitch scale in real-time; it also consumes more CPU than
* the others in the case where the pitch scale is exactly 1.0.
*/
enum Option {
OptionProcessOffline = 0x00000000,
OptionProcessRealTime = 0x00000001,
OptionStretchElastic = 0x00000000,
OptionStretchPrecise = 0x00000010,
OptionTransientsCrisp = 0x00000000,
OptionTransientsMixed = 0x00000100,
OptionTransientsSmooth = 0x00000200,
OptionPhaseLaminar = 0x00000000,
OptionPhaseIndependent = 0x00002000,
OptionThreadingAuto = 0x00000000,
OptionThreadingNever = 0x00010000,
OptionThreadingAlways = 0x00020000,
OptionWindowStandard = 0x00000000,
OptionWindowShort = 0x00100000,
OptionWindowLong = 0x00200000,
OptionFormantShifted = 0x00000000,
OptionFormantPreserved = 0x01000000,
OptionPitchHighSpeed = 0x00000000,
OptionPitchHighQuality = 0x02000000,
OptionPitchHighConsistency = 0x04000000
};
typedef int Options;
enum PresetOption {
DefaultOptions = 0x00000000,
PercussiveOptions = 0x00102000
};
/**
* 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);
~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).
*/
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).
*/
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).
*/
void setPitchScale(double scale);
/**
* Return the last time ratio value that was set (either on
* construction or with setTimeRatio()).
*/
double getTimeRatio() const;
/**
* Return the last pitch scaling ratio value that was set (either
* on construction or with setPitchScale()).
*/
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.
*/
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).
*/
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.
*/
void setPhaseOption(Options options);
/**
* Change an OptionFormant 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.
*/
void setFormantOption(Options options);
/**
* Change an OptionPitch 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).
*/
void setPitchOption(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.
*/
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).
*/
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).
*/
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.
*/
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.
*/
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.
*/
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.
*/
size_t retrieve(float *const *output, size_t samples) const;
/**
* Return the value of internal frequency cutoff value n.
*
* This function is not for general use.
*/
float getFrequencyCutoff(int n) const;
/**
* Set the value of internal frequency cutoff n to f Hz.
*
* This function is not for general use.
*/
void setFrequencyCutoff(int n, float f);
/**
* Retrieve the value of the internal input block increment value.
*
* This function is provided for diagnostic purposes only.
*/
size_t getInputIncrement() const;
/**
* In offline mode, retrieve the sequence of internal block
* increments for output, for the entire audio data, provided the
* stretch profile has been calculated. In realtime mode,
* retrieve any output increments that have accumulated since the
* last call to getOutputIncrements, to a limit of 16.
*
* This function is provided for diagnostic purposes only.
*/
std::vector<int> getOutputIncrements() const;
/**
* In offline mode, retrieve the sequence of internal phase reset
* detection function values, for the entire audio data, provided
* the stretch profile has been calculated. In realtime mode,
* retrieve any phase reset points that have accumulated since the
* last call to getPhaseResetCurve, to a limit of 16.
*
* This function is provided for diagnostic purposes only.
*/
std::vector<float> getPhaseResetCurve() const;
/**
* In offline mode, retrieve the sequence of internal frames for
* which exact timing has been sought, for the entire audio data,
* provided the stretch profile has been calculated. In realtime
* mode, return an empty sequence.
*
* This function is provided for diagnostic purposes only.
*/
std::vector<int> getExactTimePoints() const;
/**
* Return the number of channels this stretcher was constructed
* with.
*/
size_t getChannelCount() const;
/**
* Force the stretcher to calculate a stretch profile. Normally
* this happens automatically for the first process() call in
* offline mode.
*
* This function is provided for diagnostic purposes only.
*/
void calculateStretch();
/**
* Set the level of debug output. The value may be from 0 (errors
* only) to 3 (very verbose, with audible ticks in the output at
* phase reset points). The default is whatever has been set
* using setDefaultDebugLevel, or 0 if that function has not been
* called.
*/
void setDebugLevel(int level);
/**
* Set the default level of debug output for subsequently
* constructed stretchers.
*
* @see setDebugLevel
*/
static void setDefaultDebugLevel(int level);
protected:
class Impl;
Impl *m_d;
};
}
#endif

View File

@@ -1,58 +0,0 @@
/* -*- 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

View File

@@ -1,88 +0,0 @@
/*
Copyright (C) 2009 John Emmas
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __msvc_rubberband_h__
#define __msvc_rubberband_h__
#ifdef RUBBERBAND_IS_IN_WIN_STATIC_LIB // #define if your project uses librubberband (under Windows) as a static library
#define RUBBERBAND_IS_IN_WINDLL 0
#endif
#if !defined(RUBBERBAND_IS_IN_WINDLL)
#if defined(COMPILER_MSVC) || defined(COMPILER_MINGW)
// If you need '__declspec' compatibility, add extra compilers to the above as necessary
#define RUBBERBAND_IS_IN_WINDLL 1
#else
#define RUBBERBAND_IS_IN_WINDLL 0
#endif
#endif
#if RUBBERBAND_IS_IN_WINDLL && !defined(RUBBERBAND_API)
#if defined(BUILDING_RUBBERBAND)
#define RUBBERBAND_API __declspec(dllexport)
#define RUBBERBAND_APICALLTYPE __stdcall
#elif defined(COMPILER_MSVC) || defined(COMPILER_MINGW) // Probably needs Cygwin too, at some point
#define RUBBERBAND_API __declspec(dllimport)
#define RUBBERBAND_APICALLTYPE __stdcall
#else
#error "Attempting to define __declspec with an incompatible compiler !"
#endif
#elif !defined(RUBBERBAND_API)
// Other compilers / platforms could be accommodated here
#define RUBBERBAND_API
#define RUBBERBAND_APICALLTYPE
#define GETOPT_API
#define GETOPT_APICALLTYPE
#endif
#ifndef GETOPT_API
#if defined(BUILDING_GETOPT)
#define GETOPT_API __declspec(dllexport)
#define GETOPT_APICALLTYPE __cdecl
#elif defined(COMPILER_MSVC) || defined(COMPILER_MINGW) // Probably needs Cygwin too, at some point
#define GETOPT_API __declspec(dllimport)
#define GETOPT_APICALLTYPE __cdecl
#else
#error "Attempting to define __declspec with an incompatible compiler !"
#endif
#endif // GETOPT_API
#ifdef COMPILER_MSVC
#include <rpc.h>
#ifndef __THROW
#define __THROW throw()
#endif
namespace RubberBand {
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
// These are used to replicate 'dirent.h' functionality
// RUBBERBAND_API int RUBBERBAND_APICALLTYPE placeholder();
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
} // namespace Rubberband
#endif // COMPILER_MSVC
#endif // __msvc_rubberband_h__

View File

@@ -1,121 +0,0 @@
/* -*- 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-2008 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_C_API_H_
#define _RUBBERBAND_C_API_H_
#ifdef __cplusplus
extern "C" {
#endif
#define RUBBERBAND_VERSION "1.3.0-gpl"
#define RUBBERBAND_API_MAJOR_VERSION 2
#define RUBBERBAND_API_MINOR_VERSION 0
/**
* This is a C-linkage interface to the Rubber Band time stretcher.
*
* This is a wrapper interface: the primary interface is in C++ and is
* defined and documented in RubberBandStretcher.h. The library
* itself is implemented in C++, and requires C++ standard library
* support even when using the C-linkage API.
*
* Please see RubberBandStretcher.h for documentation.
*
* If you are writing to the C++ API, do not include this header.
*/
enum RubberBandOption {
RubberBandOptionProcessOffline = 0x00000000,
RubberBandOptionProcessRealTime = 0x00000001,
RubberBandOptionStretchElastic = 0x00000000,
RubberBandOptionStretchPrecise = 0x00000010,
RubberBandOptionTransientsCrisp = 0x00000000,
RubberBandOptionTransientsMixed = 0x00000100,
RubberBandOptionTransientsSmooth = 0x00000200,
RubberBandOptionPhaseLaminar = 0x00000000,
RubberBandOptionPhaseIndependent = 0x00002000,
RubberBandOptionThreadingAuto = 0x00000000,
RubberBandOptionThreadingNever = 0x00010000,
RubberBandOptionThreadingAlways = 0x00020000,
RubberBandOptionWindowStandard = 0x00000000,
RubberBandOptionWindowShort = 0x00100000,
RubberBandOptionWindowLong = 0x00200000,
RubberBandOptionFormantShifted = 0x00000000,
RubberBandOptionFormantPreserved = 0x01000000,
RubberBandOptionPitchHighQuality = 0x00000000,
RubberBandOptionPitchHighSpeed = 0x02000000,
RubberBandOptionPitchHighConsistency = 0x04000000
};
typedef int RubberBandOptions;
struct RubberBandState_;
typedef struct RubberBandState_ *RubberBandState;
extern RubberBandState rubberband_new(unsigned int sampleRate,
unsigned int channels,
RubberBandOptions options,
double initialTimeRatio,
double initialPitchScale);
extern void rubberband_delete(RubberBandState);
extern void rubberband_reset(RubberBandState);
extern void rubberband_set_time_ratio(RubberBandState, double ratio);
extern void rubberband_set_pitch_scale(RubberBandState, double scale);
extern double rubberband_get_time_ratio(const RubberBandState);
extern double rubberband_get_pitch_scale(const RubberBandState);
extern unsigned int rubberband_get_latency(const RubberBandState);
extern void rubberband_set_transients_option(RubberBandState, RubberBandOptions options);
extern void rubberband_set_phase_option(RubberBandState, RubberBandOptions options);
extern void rubberband_set_formant_option(RubberBandState, RubberBandOptions options);
extern void rubberband_set_pitch_option(RubberBandState, RubberBandOptions options);
extern void rubberband_set_expected_input_duration(RubberBandState, unsigned int samples);
extern unsigned int rubberband_get_samples_required(const RubberBandState);
extern void rubberband_set_max_process_size(RubberBandState, unsigned int samples);
extern void rubberband_study(RubberBandState, const float *const *input, unsigned int samples, int final);
extern void rubberband_process(RubberBandState, const float *const *input, unsigned int samples, int final);
extern int rubberband_available(const RubberBandState);
extern unsigned int rubberband_retrieve(const RubberBandState, float *const *output, unsigned int samples);
extern unsigned int rubberband_get_channel_count(const RubberBandState);
extern void rubberband_calculate_stretch(RubberBandState);
extern void rubberband_set_debug_level(RubberBandState, int level);
extern void rubberband_set_default_debug_level(int level);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,44 +0,0 @@
/* -*- 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-2008 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"
#include <iostream>
using namespace std;
namespace RubberBand
{
AudioCurve::AudioCurve(size_t sampleRate, size_t windowSize) :
m_sampleRate(sampleRate),
m_windowSize(windowSize)
{
}
AudioCurve::~AudioCurve()
{
}
float
AudioCurve::processDouble(const double *R__ mag, size_t increment)
{
cerr << "AudioCurve::processDouble: WARNING: Using inefficient and lossy conversion for AudioCurve::process(float)" << endl;
float *tmp = new float[m_windowSize];
for (int i = 0; i < int(m_windowSize); ++i) tmp[i] = float(mag[i]);
float df = process(tmp, increment);
delete[] tmp;
return df;
}
}

View File

@@ -1,45 +0,0 @@
/* -*- 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-2008 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>
#include "sysutils.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(const float *R__ mag, size_t increment) = 0;
virtual float processDouble(const double *R__ mag, size_t increment);
virtual void reset() = 0;
protected:
size_t m_sampleRate;
size_t m_windowSize;
};
}
#endif

View File

@@ -1,53 +0,0 @@
/* -*- 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-2008 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(const float *R__, size_t)
{
return 1.f;
}
float
ConstantAudioCurve::processDouble(const double *R__, size_t)
{
return 1.f;
}
}

View File

@@ -1,38 +0,0 @@
/* -*- 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-2008 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(const float *R__ mag, size_t increment);
virtual float processDouble(const double *R__ mag, size_t increment);
virtual void reset();
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,80 +0,0 @@
/* -*- 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-2008 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_
#include "sysutils.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(int size, int debugLevel = 0); // may throw InvalidSize
~FFT();
void forward(const double *R__ realIn, double *R__ realOut, double *R__ imagOut);
void forwardPolar(const double *R__ realIn, double *R__ magOut, double *R__ phaseOut);
void forwardMagnitude(const double *R__ realIn, double *R__ magOut);
void forward(const float *R__ realIn, float *R__ realOut, float *R__ imagOut);
void forwardPolar(const float *R__ realIn, float *R__ magOut, float *R__ phaseOut);
void forwardMagnitude(const float *R__ realIn, float *R__ magOut);
void inverse(const double *R__ realIn, const double *R__ imagIn, double *R__ realOut);
void inversePolar(const double *R__ magIn, const double *R__ phaseIn, double *R__ realOut);
void inverseCepstral(const double *R__ magIn, double *R__ cepOut);
void inverse(const float *R__ realIn, const float *R__ imagIn, float *R__ realOut);
void inversePolar(const float *R__ magIn, const float *R__ phaseIn, float *R__ realOut);
void inverseCepstral(const float *R__ magIn, float *R__ cepOut);
// 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

View File

@@ -1,69 +0,0 @@
/* -*- 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-2008 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(const float *R__ mag, size_t /*increment*/)
{
float result = 0.0;
const int sz = m_windowSize / 2;
for (int n = 0; n <= sz; ++n) {
result = result + mag[n] * n;
}
return result;
}
float
HighFrequencyAudioCurve::processDouble(const double *R__ mag, size_t /*increment*/)
{
float result = 0.0;
const int sz = m_windowSize / 2;
for (int n = 0; n <= sz; ++n) {
result = result + (float)mag[n] * n;
}
return result;
}
}

View File

@@ -1,40 +0,0 @@
/* -*- 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-2008 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(const float *R__ mag, size_t increment);
virtual float processDouble(const double *R__ mag, size_t increment);
virtual void reset();
};
}
#endif

View File

@@ -1,112 +0,0 @@
/* -*- 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-2008 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 "Profiler.h"
#include <cmath>
namespace RubberBand
{
PercussiveAudioCurve::PercussiveAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurve(sampleRate, windowSize)
{
m_prevMag = new float[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)
{
m_windowSize = newSize;
delete[] m_prevMag;
m_prevMag = new float[m_windowSize/2 + 1];
reset();
}
float
PercussiveAudioCurve::process(const float *R__ mag, size_t /*increment*/)
{
static float threshold = powf(10.f, 0.15f); // 3dB rise in square of magnitude
static float zeroThresh = powf(10.f, -8);
size_t count = 0;
size_t nonZeroCount = 0;
const int sz = m_windowSize / 2;
for (int n = 1; n <= sz; ++n) {
bool above = ((mag[n] / m_prevMag[n]) >= threshold);
if (above) ++count;
if (mag[n] > zeroThresh) ++nonZeroCount;
}
for (int n = 1; n <= sz; ++n) {
m_prevMag[n] = mag[n];
}
if (nonZeroCount == 0) return 0;
else return float(count) / float(nonZeroCount);
}
float
PercussiveAudioCurve::processDouble(const double *R__ mag, size_t /*increment*/)
{
Profiler profiler("PercussiveAudioCurve::process");
static double threshold = pow(10.0, 0.15); // 3dB rise in square of magnitude
static double zeroThresh = pow(10.0, -8);
size_t count = 0;
size_t nonZeroCount = 0;
const int sz = m_windowSize / 2;
for (int n = 1; n <= sz; ++n) {
bool above = ((mag[n] / m_prevMag[n]) >= threshold);
if (above) ++count;
if (mag[n] > zeroThresh) ++nonZeroCount;
}
for (int n = 1; n <= sz; ++n) {
m_prevMag[n] = mag[n];
}
if (nonZeroCount == 0) return 0;
else return float(count) / float(nonZeroCount);
}
}

View File

@@ -1,42 +0,0 @@
/* -*- 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-2008 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(const float *R__ mag, size_t increment);
virtual float processDouble(const double *R__ mag, size_t increment);
virtual void reset();
protected:
float *R__ m_prevMag;
};
}
#endif

View File

@@ -1,176 +0,0 @@
/* -*- 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-2008 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 "Profiler.h"
#include <algorithm>
#include <set>
#include <string>
#include <map>
#include <cstdio>
namespace RubberBand {
#ifndef NO_TIMING
Profiler::ProfileMap
Profiler::m_profiles;
Profiler::WorstCallMap
Profiler::m_worstCalls;
void
Profiler::add(const char *id, float ms)
{
ProfileMap::iterator pmi = m_profiles.find(id);
if (pmi != m_profiles.end()) {
++pmi->second.first;
pmi->second.second += ms;
} else {
m_profiles[id] = TimePair(1, ms);
}
WorstCallMap::iterator wci = m_worstCalls.find(id);
if (wci != m_worstCalls.end()) {
if (ms > wci->second) wci->second = ms;
} else {
m_worstCalls[id] = ms;
}
}
void
Profiler::dump()
{
#ifdef PROFILE_CLOCKS
fprintf(stderr, "Profiling points [CPU time]:\n");
#else
fprintf(stderr, "Profiling points [Wall time]:\n");
#endif
fprintf(stderr, "\nBy name:\n");
typedef std::set<const char *, std::less<std::string> > StringSet;
StringSet profileNames;
for (ProfileMap::const_iterator i = m_profiles.begin();
i != m_profiles.end(); ++i) {
profileNames.insert(i->first);
}
for (StringSet::const_iterator i = profileNames.begin();
i != profileNames.end(); ++i) {
ProfileMap::const_iterator j = m_profiles.find(*i);
if (j == m_profiles.end()) continue;
const TimePair &pp(j->second);
fprintf(stderr, "%s(%d):\n", *i, pp.first);
fprintf(stderr, "\tReal: \t%f ms \t[%f ms total]\n",
(pp.second / pp.first),
(pp.second));
WorstCallMap::const_iterator k = m_worstCalls.find(*i);
if (k == m_worstCalls.end()) continue;
fprintf(stderr, "\tWorst:\t%f ms/call\n", k->second);
}
typedef std::multimap<float, const char *> TimeRMap;
typedef std::multimap<int, const char *> IntRMap;
TimeRMap totmap, avgmap, worstmap;
IntRMap ncallmap;
for (ProfileMap::const_iterator i = m_profiles.begin();
i != m_profiles.end(); ++i) {
totmap.insert(TimeRMap::value_type(i->second.second, i->first));
avgmap.insert(TimeRMap::value_type(i->second.second /
i->second.first, i->first));
ncallmap.insert(IntRMap::value_type(i->second.first, i->first));
}
for (WorstCallMap::const_iterator i = m_worstCalls.begin();
i != m_worstCalls.end(); ++i) {
worstmap.insert(TimeRMap::value_type(i->second, i->first));
}
fprintf(stderr, "\nBy total:\n");
for (TimeRMap::const_iterator i = totmap.end(); i != totmap.begin(); ) {
--i;
fprintf(stderr, "%-40s %f ms\n", i->second, i->first);
}
fprintf(stderr, "\nBy average:\n");
for (TimeRMap::const_iterator i = avgmap.end(); i != avgmap.begin(); ) {
--i;
fprintf(stderr, "%-40s %f ms\n", i->second, i->first);
}
fprintf(stderr, "\nBy worst case:\n");
for (TimeRMap::const_iterator i = worstmap.end(); i != worstmap.begin(); ) {
--i;
fprintf(stderr, "%-40s %f ms\n", i->second, i->first);
}
fprintf(stderr, "\nBy number of calls:\n");
for (IntRMap::const_iterator i = ncallmap.end(); i != ncallmap.begin(); ) {
--i;
fprintf(stderr, "%-40s %d\n", i->second, i->first);
}
}
Profiler::Profiler(const char* c) :
m_c(c),
m_ended(false)
{
#ifdef PROFILE_CLOCKS
m_start = clock();
#else
(void)gettimeofday(&m_start, 0);
#endif
}
Profiler::~Profiler()
{
if (!m_ended) end();
}
void
Profiler::end()
{
#ifdef PROFILE_CLOCKS
clock_t end = clock();
clock_t elapsed = end - m_start;
float ms = float((double(elapsed) / double(CLOCKS_PER_SEC)) * 1000.0);
#else
struct timeval tv;
(void)gettimeofday(&tv, 0);
tv.tv_sec -= m_start.tv_sec;
if (tv.tv_usec < m_start.tv_usec) {
tv.tv_usec += 1000000;
tv.tv_sec -= 1;
}
tv.tv_usec -= m_start.tv_usec;
float ms = float((double(tv.tv_sec) + (double(tv.tv_usec) / 1000000.0)) * 1000.0);
#endif
add(m_c, ms);
m_ended = true;
}
#endif
}

View File

@@ -1,91 +0,0 @@
/* -*- 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-2008 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 _PROFILER_H_
#define _PROFILER_H_
#define NO_TIMING 1
//#define WANT_TIMING 1
//#define PROFILE_CLOCKS 1
#ifdef NDEBUG
#ifndef WANT_TIMING
#define NO_TIMING 1
#endif
#endif
#ifndef NO_TIMING
#ifdef PROFILE_CLOCKS
#include <time.h>
#else
#include "sysutils.h"
#ifndef PLATFORM_WINDOWS
#include <sys/time.h>
#endif
#endif
#endif
#include <map>
namespace RubberBand {
#ifndef NO_TIMING
class Profiler
{
public:
Profiler(const char *name);
~Profiler();
void end(); // same action as dtor
static void dump();
protected:
const char* m_c;
#ifdef PROFILE_CLOCKS
clock_t m_start;
#else
struct timeval m_start;
#endif
bool m_showOnDestruct;
bool m_ended;
typedef std::pair<int, float> TimePair;
typedef std::map<const char *, TimePair> ProfileMap;
typedef std::map<const char *, float> WorstCallMap;
static ProfileMap m_profiles;
static WorstCallMap m_worstCalls;
static void add(const char *, float);
};
#else
class Profiler
{
public:
Profiler(const char *) { }
~Profiler() { }
void update() const { }
void end() { }
static void dump() { }
};
#endif
}
#endif

View File

@@ -1,261 +0,0 @@
/* -*- 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-2008 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 "Profiler.h"
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <samplerate.h>
namespace RubberBand {
class ResamplerImpl
{
public:
virtual ~ResamplerImpl() { }
virtual int resample(const float *const R__ *const R__ in,
float *const R__ *const R__ out,
int incount,
float ratio,
bool final) = 0;
virtual void reset() = 0;
};
namespace Resamplers {
class D_SRC : public ResamplerImpl
{
public:
D_SRC(Resampler::Quality quality, int channels, int maxBufferSize,
int m_debugLevel);
~D_SRC();
int resample(const float *const R__ *const R__ in,
float *const R__ *const R__ out,
int incount,
float ratio,
bool final);
void reset();
protected:
SRC_STATE *m_src;
float *m_iin;
float *m_iout;
float m_lastRatio;
int m_channels;
int m_iinsize;
int m_ioutsize;
int m_debugLevel;
};
D_SRC::D_SRC(Resampler::Quality quality, int channels, int maxBufferSize,
int debugLevel) :
m_src(0),
m_iin(0),
m_iout(0),
m_lastRatio(1.f),
m_channels(channels),
m_iinsize(0),
m_ioutsize(0),
m_debugLevel(debugLevel)
{
if (m_debugLevel > 0) {
std::cerr << "Resampler::Resampler: using libsamplerate implementation"
<< std::endl;
}
int err = 0;
m_src = src_new(quality == Resampler::Best ? SRC_SINC_BEST_QUALITY :
quality == Resampler::Fastest ? SRC_LINEAR :
SRC_SINC_FASTEST,
channels, &err);
if (err) {
std::cerr << "Resampler::Resampler: failed to create libsamplerate resampler: "
<< src_strerror(err) << std::endl;
throw Resampler::ImplementationError; //!!! of course, need to catch this!
}
if (maxBufferSize > 0 && m_channels > 1) {
m_iinsize = maxBufferSize * m_channels;
m_ioutsize = maxBufferSize * m_channels * 2;
m_iin = allocFloat(m_iinsize);
m_iout = allocFloat(m_ioutsize);
}
reset();
}
D_SRC::~D_SRC()
{
src_delete(m_src);
if (m_iinsize > 0) {
free(m_iin);
}
if (m_ioutsize > 0) {
free(m_iout);
}
}
int
D_SRC::resample(const float *const R__ *const R__ in,
float *const R__ *const R__ out,
int incount,
float ratio,
bool final)
{
SRC_DATA data;
int outcount = lrintf(ceilf(incount * ratio));
if (m_channels == 1) {
data.data_in = const_cast<float *>(*in); //!!!???
data.data_out = *out;
} else {
if (incount * m_channels > m_iinsize) {
m_iinsize = incount * m_channels;
m_iin = allocFloat(m_iin, m_iinsize);
}
if (outcount * m_channels > m_ioutsize) {
m_ioutsize = outcount * m_channels;
m_iout = allocFloat(m_iout, m_ioutsize);
}
for (int i = 0; i < incount; ++i) {
for (int 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 = 0;
err = src_process(m_src, &data);
if (err) {
std::cerr << "Resampler::process: libsamplerate error: "
<< src_strerror(err) << std::endl;
throw Resampler::ImplementationError; //!!! of course, need to catch this!
}
if (m_channels > 1) {
for (int i = 0; i < data.output_frames_gen; ++i) {
for (int c = 0; c < m_channels; ++c) {
out[c][i] = m_iout[i * m_channels + c];
}
}
}
m_lastRatio = ratio;
return data.output_frames_gen;
}
void
D_SRC::reset()
{
src_reset(m_src);
}
} /* end namespace Resamplers */
Resampler::Resampler(Resampler::Quality quality, int channels,
int maxBufferSize, int debugLevel)
{
m_method = -1;
switch (quality) {
case Resampler::Best:
m_method = 1;
break;
case Resampler::FastestTolerable:
m_method = 1;
break;
case Resampler::Fastest:
m_method = 1;
break;
}
if (m_method == -1) {
std::cerr << "Resampler::Resampler(" << quality << ", " << channels
<< ", " << maxBufferSize << "): No implementation available!"
<< std::endl;
abort();
}
switch (m_method) {
case 0:
std::cerr << "Resampler::Resampler(" << quality << ", " << channels
<< ", " << maxBufferSize << "): No implementation available!"
<< std::endl;
abort();
break;
case 1:
d = new Resamplers::D_SRC(quality, channels, maxBufferSize, debugLevel);
break;
case 2:
std::cerr << "Resampler::Resampler(" << quality << ", " << channels
<< ", " << maxBufferSize << "): No implementation available!"
<< std::endl;
abort();
break;
}
}
Resampler::~Resampler()
{
delete d;
}
int
Resampler::resample(const float *const R__ *const R__ in,
float *const R__ *const R__ out,
int incount, float ratio, bool final)
{
Profiler profiler("Resampler::resample");
return d->resample(in, out, incount, ratio, final);
}
void
Resampler::reset()
{
d->reset();
}
}

View File

@@ -1,57 +0,0 @@
/* -*- 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-2008 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>
#include "sysutils.h"
namespace RubberBand {
class ResamplerImpl;
class Resampler
{
public:
enum Quality { Best, FastestTolerable, Fastest };
enum Exception { ImplementationError };
/**
* 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, int channels, int maxBufferSize = 0,
int debugLevel = 0);
~Resampler();
int resample(const float *const R__ *const R__ in,
float *const R__ *const R__ out,
int incount,
float ratio,
bool final = false);
void reset();
protected:
ResamplerImpl *d;
int m_method;
};
}
#endif

View File

@@ -1,670 +0,0 @@
/* -*- 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-2008 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 <cstring>
#include <sys/types.h>
#include <cstring>
#ifndef PLATFORM_WINDOWS
#include <sys/mman.h>
#endif
#include "Scavenger.h"
#include "Profiler.h"
//#define DEBUG_RINGBUFFER 1
#ifdef PLATFORM_WINDOWS
#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(int n);
virtual ~RingBuffer();
/**
* Return the total capacity of the ring buffer in samples.
* (This is the argument n passed to the constructor.)
*/
int 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(int 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(int 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.
*/
int getReadSpace(int R = 0) const;
/**
* Return the amount of space available for writing, in samples.
*/
int 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.
*/
int read(T *R__ destination, int 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.
*/
int readAdding(T *R__ destination, int 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.
*/
int peek(T *R__ destination, int 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.
*/
int skip(int 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.
*/
int write(const T *source, int 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.
*/
int zero(int n);
protected:
T *R__ m_buffer;
volatile int m_writer;
volatile int m_readers[N];
int 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(int 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>
int
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(int 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(int newSize, int R) const
{
RingBuffer<T, N> *newBuffer = new RingBuffer<T, N>(newSize);
int w = m_writer;
int 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>
int
RingBuffer<T, N>::getReadSpace(int R) const
{
int writer = m_writer;
int reader = m_readers[R];
int 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>
int
RingBuffer<T, N>::getWriteSpace() const
{
int space = 0;
for (int i = 0; i < N; ++i) {
int writer = m_writer;
int reader = m_readers[i];
int here = (reader + m_size - writer - 1);
if (here >= m_size) here -= m_size;
if (i == 0 || here < space) space = here;
}
#ifdef DEBUG_RINGBUFFER
int 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>
int
RingBuffer<T, N>::read(T *R__ destination, int n, int R)
{
Profiler profiler("RingBuffer::read");
#ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read(dest, " << n << ", " << R << ")" << std::endl;
#endif
int available = getReadSpace(R);
if (n > available) {
#ifdef DEBUG_RINGBUFFER
std::cerr << "WARNING: Only " << available << " samples available"
<< std::endl;
#endif
for (int i = available; i < n; ++i) {
destination[i] = 0;
}
n = available;
}
if (n == 0) return n;
int reader = m_readers[R];
int here = m_size - reader;
T *const R__ bufbase = m_buffer + reader;
if (here >= n) {
for (int i = 0; i < n; ++i) {
destination[i] = bufbase[i];
}
} else {
for (int i = 0; i < here; ++i) {
destination[i] = bufbase[i];
}
T *const R__ destbase = destination + here;
const int nh = n - here;
for (int i = 0; i < nh; ++i) {
destbase[i] = 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>
int
RingBuffer<T, N>::readAdding(T *R__ destination, int n, int R)
{
Profiler profiler("RingBuffer::readAdding");
#ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readAdding(dest, " << n << ", " << R << ")" << std::endl;
#endif
int 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;
int reader = m_readers[R];
int here = m_size - reader;
const T *const R__ bufbase = m_buffer + reader;
if (here >= n) {
for (int i = 0; i < n; ++i) {
destination[i] += bufbase[i];
}
} else {
for (int i = 0; i < here; ++i) {
destination[i] += bufbase[i];
}
T *const R__ destbase = destination + here;
const int nh = n - here;
for (int i = 0; i < nh; ++i) {
destbase[i] += 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;
}
int 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>
int
RingBuffer<T, N>::peek(T *R__ destination, int n, int R) const
{
Profiler profiler("RingBuffer::peek");
#ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(dest, " << n << ", " << R << ")" << std::endl;
#endif
int 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;
int reader = m_readers[R];
int here = m_size - reader;
const T *const R__ bufbase = m_buffer + reader;
if (here >= n) {
for (int i = 0; i < n; ++i) {
destination[i] = bufbase[i];
}
} else {
for (int i = 0; i < here; ++i) {
destination[i] = bufbase[i];
}
T *const R__ destbase = destination + here;
const int nh = n - here;
for (int i = 0; i < nh; ++i) {
destbase[i] = 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>
int
RingBuffer<T, N>::skip(int n, int R)
{
#ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::skip(" << n << ", " << R << ")" << std::endl;
#endif
int 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;
int reader = m_readers[R];
reader += n;
while (reader >= m_size) reader -= m_size;
m_readers[R] = reader;
return n;
}
template <typename T, int N>
int
RingBuffer<T, N>::write(const T *source, int n)
{
Profiler profiler("RingBuffer::write");
#ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write(" << n << ")" << std::endl;
#endif
int 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;
int writer = m_writer;
int here = m_size - writer;
T *const R__ bufbase = m_buffer + writer;
if (here >= n) {
for (int i = 0; i < n; ++i) {
bufbase[i] = source[i];
}
} else {
for (int i = 0; i < here; ++i) {
bufbase[i] = source[i];
}
const int nh = n - here;
const T *const R__ srcbase = source + here;
T *const R__ buf = m_buffer;
for (int i = 0; i < nh; ++i) {
buf[i] = srcbase[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>
int
RingBuffer<T, N>::zero(int n)
{
Profiler profiler("RingBuffer::zero");
#ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::zero(" << n << ")" << std::endl;
#endif
int 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;
int writer = m_writer;
int here = m_size - writer;
T *const R__ bufbase = m_buffer + writer;
if (here >= n) {
for (int i = 0; i < n; ++i) {
bufbase[i] = 0;
}
} else {
for (int i = 0; i < here; ++i) {
bufbase[i] = 0;
}
const int nh = n - here;
for (int i = 0; i < nh; ++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;
}
}
//#include "RingBuffer.cpp"
#endif // _RINGBUFFER_H_

View File

@@ -1,200 +0,0 @@
/* -*- 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-2008 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) :
m_d(new Impl(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::setFormantOption(Options options)
{
m_d->setFormantOption(options);
}
void
RubberBandStretcher::setPitchOption(Options options)
{
m_d->setPitchOption(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);
}
}

View File

@@ -1,202 +0,0 @@
/* -*- 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-2008 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 <iostream>
#ifndef PLATFORM_WINDOWS
#include <sys/time.h>
#endif
#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

View File

@@ -1,69 +0,0 @@
/* -*- 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-2008 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 "SilentAudioCurve.h"
#include <cmath>
namespace RubberBand
{
SilentAudioCurve::SilentAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurve(sampleRate, windowSize)
{
}
SilentAudioCurve::~SilentAudioCurve()
{
}
void
SilentAudioCurve::reset()
{
}
void
SilentAudioCurve::setWindowSize(size_t newSize)
{
m_windowSize = newSize;
}
float
SilentAudioCurve::process(const float *R__ mag, size_t)
{
const int hs = m_windowSize / 2;
static float threshold = powf(10.f, -6);
for (int i = 0; i <= hs; ++i) {
if (mag[i] > threshold) return 0.f;
}
return 1.f;
}
float
SilentAudioCurve::processDouble(const double *R__ mag, size_t)
{
const int hs = m_windowSize / 2;
static double threshold = pow(10.0, -6);
for (int i = 0; i <= hs; ++i) {
if (mag[i] > threshold) return 0.f;
}
return 1.f;
}
}

View File

@@ -1,38 +0,0 @@
/* -*- 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-2008 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 _SILENT_AUDIO_CURVE_H_
#define _SILENT_AUDIO_CURVE_H_
#include "AudioCurve.h"
namespace RubberBand
{
class SilentAudioCurve : public AudioCurve
{
public:
SilentAudioCurve(size_t sampleRate, size_t windowSize);
virtual ~SilentAudioCurve();
virtual void setWindowSize(size_t newSize);
virtual float process(const float *R__ mag, size_t increment);
virtual float processDouble(const double *R__ mag, size_t increment);
virtual void reset();
};
}
#endif

View File

@@ -1,83 +0,0 @@
/* -*- 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-2008 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 float[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)
{
delete[] m_prevMag;
m_windowSize = newSize;
m_prevMag = new float[m_windowSize/2 + 1];
reset();
}
float
SpectralDifferenceAudioCurve::process(const float *R__ 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;
}
float
SpectralDifferenceAudioCurve::processDouble(const double *R__ 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] = (float)mag[n];
}
return result;
}
}

View File

@@ -1,43 +0,0 @@
/* -*- 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-2008 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(const float *R__ mag, size_t increment);
virtual float processDouble(const double *R__ mag, size_t increment);
virtual void reset();
protected:
float *R__ m_prevMag;
};
}
#endif

View File

@@ -1,802 +0,0 @@
/* -*- 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-2008 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.
*/
#ifdef COMPILER_MSVC
#include "bsd-3rdparty/float_cast/float_cast.h"
#endif
#include "StretchCalculator.h"
#include <algorithm>
#include <math.h>
#include <algorithm>
#include <iostream>
#include <deque>
#include <set>
#include <cassert>
#include <algorithm>
#include "sysutils.h"
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,
float df,
size_t increment)
{
if (increment == 0) increment = m_increment;
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.35f;
if (ratio > 1) transientThreshold = 0.25f;
if (m_useHardPeaks && df > m_prevDf * 1.1f && df > transientThreshold) {
isTransient = true;
}
if (m_debugLevel > 2) {
std::cerr << "df = " << df << ", prevDf = " << m_prevDf
<< ", thresh = " << transientThreshold << std::endl;
}
m_prevDf = df;
bool ratioChanged = (ratio != m_prevRatio);
m_prevRatio = ratio;
if (isTransient && m_transientAmnesty == 0) {
if (m_debugLevel > 1) {
std::cerr << "StretchCalculator::calculateSingle: transient"
<< std::endl;
}
m_divergence += increment - (increment * ratio);
// as in offline mode, 0.05 sec approx min between transients
m_transientAmnesty =
lrint(ceil(double(m_sampleRate) / (20 * double(increment))));
m_recovery = m_divergence / ((m_sampleRate / 10.0) / increment);
return -int(increment);
}
if (ratioChanged) {
m_recovery = m_divergence / ((m_sampleRate / 10.0) / increment);
}
if (m_transientAmnesty > 0) --m_transientAmnesty;
int incr = lrint(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((increment * ratio) / 2)) {
incr = lrint((increment * ratio) / 2);
} else if (incr > lrint(increment * ratio * 2)) {
incr = lrint(increment * ratio * 2);
}
double divdiff = (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) / 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;
}
}
}
}

View File

@@ -1,98 +0,0 @@
/* -*- 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-2008 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().
*
* If increment is non-zero, use it for the input increment for
* this block in preference to m_increment.
*/
virtual int calculateSingle(double ratio, float curveValue,
size_t increment = 0);
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> &regionCurve,
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

View File

@@ -1,305 +0,0 @@
/* -*- 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-2008 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 "StretcherChannelData.h"
#include "Resampler.h"
namespace RubberBand
{
RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize,
int overSample,
size_t outbufSize) :
oversample(overSample)
{
std::set<size_t> s;
construct(s, windowSize, outbufSize);
}
RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &windowSizes,
int overSample,
size_t initialWindowSize,
size_t outbufSize) :
oversample(overSample)
{
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;
}
// max size of the real "half" of freq data
size_t realSize = (maxSize * oversample)/2 + 1;
// 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 = allocDouble(realSize);
phase = allocDouble(realSize);
prevPhase = allocDouble(realSize);
prevError = allocDouble(realSize);
unwrappedPhase = allocDouble(realSize);
envelope = allocDouble(realSize);
freqPeak = new size_t[realSize];
fltbuf = allocFloat(maxSize);
accumulator = allocFloat(maxSize);
windowAccumulator = allocFloat(maxSize);
for (std::set<size_t>::const_iterator i = windowSizes.begin();
i != windowSizes.end(); ++i) {
ffts[*i] = new FFT(*i * oversample);
ffts[*i]->initDouble();
}
if (windowSizes.find(initialWindowSize) == windowSizes.end()) {
ffts[initialWindowSize] = new FFT(initialWindowSize * oversample);
ffts[initialWindowSize]->initDouble();
}
fft = ffts[initialWindowSize];
dblbuf = fft->getDoubleTimeBuffer();
resampler = 0;
resamplebuf = 0;
resamplebufSize = 0;
reset();
for (size_t i = 0; i < realSize; ++i) {
freqPeak[i] = 0;
}
for (size_t i = 0; i < initialWindowSize * oversample; ++i) {
dblbuf[i] = 0.0;
}
for (size_t i = 0; i < maxSize; ++i) {
accumulator[i] = 0.f;
windowAccumulator[i] = 0.f;
}
// Avoid dividing opening sample (which will be discarded anyway) by zero
windowAccumulator[0] = 1.f;
}
void
RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
{
size_t oldSize = inbuf->getSize();
size_t realSize = (windowSize * oversample) / 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 * oversample);
ffts[windowSize]->initDouble();
}
fft = ffts[windowSize];
dblbuf = fft->getDoubleTimeBuffer();
for (size_t i = 0; i < windowSize * oversample; ++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;
prevError[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
mag = allocDouble(mag, realSize);
phase = allocDouble(phase, realSize);
prevPhase = allocDouble(prevPhase, realSize);
prevError = allocDouble(prevError, realSize);
unwrappedPhase = allocDouble(unwrappedPhase, realSize);
envelope = allocDouble(envelope, realSize);
delete[] freqPeak;
freqPeak = new size_t[realSize];
fltbuf = allocFloat(fltbuf, windowSize);
// But we do want to preserve data in these
float *newAcc = allocFloat(windowSize);
for (size_t i = 0; i < oldSize; ++i) newAcc[i] = accumulator[i];
freeFloat(accumulator);
accumulator = newAcc;
newAcc = allocFloat(windowSize);
for (size_t i = 0; i < oldSize; ++i) newAcc[i] = windowAccumulator[i];
freeFloat(windowAccumulator);
windowAccumulator = newAcc;
//!!! and resampler?
for (size_t i = 0; i < realSize; ++i) {
freqPeak[i] = 0;
}
for (size_t i = 0; i < windowSize; ++i) {
fltbuf[i] = 0.f;
}
if (ffts.find(windowSize) == ffts.end()) {
ffts[windowSize] = new FFT(windowSize * oversample);
ffts[windowSize]->initDouble();
}
fft = ffts[windowSize];
dblbuf = fft->getDoubleTimeBuffer();
for (size_t i = 0; i < windowSize * oversample; ++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;
}
}
void
RubberBandStretcher::Impl::ChannelData::setResampleBufSize(size_t sz)
{
resamplebuf = allocFloat(resamplebuf, sz);
resamplebufSize = sz;
}
RubberBandStretcher::Impl::ChannelData::~ChannelData()
{
delete resampler;
freeFloat(resamplebuf);
delete inbuf;
delete outbuf;
freeDouble(mag);
freeDouble(phase);
freeDouble(prevPhase);
freeDouble(prevError);
freeDouble(unwrappedPhase);
freeDouble(envelope);
delete[] freqPeak;
freeFloat(accumulator);
freeFloat(windowAccumulator);
freeFloat(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();
size_t size = inbuf->getSize();
for (size_t i = 0; i < size; ++i) {
accumulator[i] = 0.f;
windowAccumulator[i] = 0.f;
}
// Avoid dividing opening sample (which will be discarded anyway) by zero
windowAccumulator[0] = 1.f;
accumulatorFill = 0;
prevIncrement = 0;
chunkCount = 0;
inCount = 0;
inputSize = -1;
outCount = 0;
unchanged = true;
draining = false;
outputComplete = false;
}
}

View File

@@ -1,135 +0,0 @@
/* -*- 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-2008 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>
//#define EXPERIMENT 1
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, int overSample, 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,
int overSample, 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);
/**
* Set the resampler buffer size. Default if not called is no
* buffer allocated at all.
*/
void setResampleBufSize(size_t resamplebufSize);
RingBuffer<float> *inbuf;
RingBuffer<float> *outbuf;
double *mag;
double *phase;
double *prevPhase;
double *prevError;
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
double *envelope; // for cepstral formant shift
bool unchanged;
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;
int oversample;
private:
void construct(const std::set<size_t> &windowSizes,
size_t initialWindowSize, size_t outbufSize);
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,202 +0,0 @@
/* -*- 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-2008 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(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 setFormantOption(Options);
void setPitchOption(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:
size_t m_sampleRate;
size_t m_channels;
size_t consumeChannel(size_t channel, const float *input,
size_t samples, bool final);
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 formantShiftChunk(size_t channel);
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
bool resampleBeforeStretching() const;
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;
std::vector<bool> m_silence;
int m_silentHistory;
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;
AudioCurve *m_silentAudioCurve;
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

File diff suppressed because it is too large Load Diff

View File

@@ -1,583 +0,0 @@
/* -*- 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-2008 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 <cstdlib>
#include <iostream>
#ifndef COMPILER_MSVC
#include <sys/time.h>
#include <time.h>
#endif
using std::cerr;
using std::endl;
using std::string;
namespace RubberBand
{
#ifdef PLATFORM_WINDOWS
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()
#ifndef NO_THREAD_CHECKS
:
m_lockedBy(-1)
#endif
{
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()
{
#ifndef NO_THREAD_CHECKS
DWORD tid = GetCurrentThreadId();
if (m_lockedBy == tid) {
cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl;
}
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl;
#endif
WaitForSingleObject(m_mutex, INFINITE);
#ifndef NO_THREAD_CHECKS
m_lockedBy = tid;
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl;
#endif
}
void
Mutex::unlock()
{
#ifndef NO_THREAD_CHECKS
DWORD tid = GetCurrentThreadId();
if (m_lockedBy != tid) {
cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl;
return;
}
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl;
#endif
#ifndef NO_THREAD_CHECKS
m_lockedBy = -1;
#endif
ReleaseMutex(m_mutex);
}
bool
Mutex::trylock()
{
#ifndef NO_THREAD_CHECKS
DWORD tid = GetCurrentThreadId();
#endif
DWORD result = WaitForSingleObject(m_mutex, 0);
if (result == WAIT_TIMEOUT || result == WAIT_FAILED) {
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl;
#endif
return false;
} else {
#ifndef NO_THREAD_CHECKS
m_lockedBy = tid;
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl;
#endif
return true;
}
}
Condition::Condition(string name) :
m_locked(false)
#ifdef DEBUG_CONDITION
, m_name(name)
#endif
{
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 /* !PLATFORM_WINDOWS */
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()
#ifndef NO_THREAD_CHECKS
:
m_lockedBy(0),
m_locked(false)
#endif
{
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()
{
#ifndef NO_THREAD_CHECKS
pthread_t tid = pthread_self();
if (m_locked && m_lockedBy == tid) {
cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl;
}
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl;
#endif
pthread_mutex_lock(&m_mutex);
#ifndef NO_THREAD_CHECKS
m_lockedBy = tid;
m_locked = true;
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl;
#endif
}
void
Mutex::unlock()
{
#ifndef NO_THREAD_CHECKS
pthread_t tid = pthread_self();
if (!m_locked) {
cerr << "ERROR: Mutex " << &m_mutex << " not locked in unlock" << endl;
return;
} else if (m_lockedBy != tid) {
cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl;
return;
}
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl;
#endif
#ifndef NO_THREAD_CHECKS
m_locked = false;
#endif
pthread_mutex_unlock(&m_mutex);
}
bool
Mutex::trylock()
{
#ifndef NO_THREAD_CHECKS
pthread_t tid = pthread_self();
#endif
if (pthread_mutex_trylock(&m_mutex)) {
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl;
#endif
return false;
} else {
#ifndef NO_THREAD_CHECKS
m_lockedBy = tid;
m_locked = true;
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl;
#endif
return true;
}
}
Condition::Condition(string /*name*/) :
m_locked(false)
#ifdef DEBUG_CONDITION
, m_name(name)
#endif
{
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 /* !PLATFORM_WINDOWS */
MutexLocker::MutexLocker(Mutex *mutex) :
m_mutex(mutex)
{
if (m_mutex) {
m_mutex->lock();
}
}
MutexLocker::~MutexLocker()
{
if (m_mutex) {
m_mutex->unlock();
}
}
}

View File

@@ -1,142 +0,0 @@
/* -*- 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-2008 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 PLATFORM_WINDOWS
#include <windows.h>
#else /* !PLATFORM_WINDOWS */
#include <pthread.h>
#endif /* !PLATFORM_WINDOWS */
#include <string>
//#define DEBUG_THREAD 1
//#define DEBUG_MUTEX 1
//#define DEBUG_CONDITION 1
namespace RubberBand
{
class Thread
{
public:
#ifdef PLATFORM_WINDOWS
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 PLATFORM_WINDOWS
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 PLATFORM_WINDOWS
HANDLE m_mutex;
#ifndef NO_THREAD_CHECKS
DWORD m_lockedBy;
#endif
#else
pthread_mutex_t m_mutex;
#ifndef NO_THREAD_CHECKS
pthread_t m_lockedBy;
bool m_locked;
#endif
#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 PLATFORM_WINDOWS
HANDLE m_mutex;
HANDLE m_condition;
bool m_locked;
#else
pthread_mutex_t m_mutex;
pthread_cond_t m_condition;
bool m_locked;
#endif
#ifdef DEBUG_CONDITION
std::string m_name;
#endif
};
}
#endif

View File

@@ -1,17 +0,0 @@
/* -*- 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-2008 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 "Window.h"

View File

@@ -1,183 +0,0 @@
/* -*- 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-2008 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 <cstdlib>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <cstdlib>
#include <map>
#include "sysutils.h"
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, int 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 *R__ src) const
{
const int sz = m_size;
for (int i = 0; i < sz; ++i) {
src[i] *= m_cache[i];
}
}
void cut(T *R__ src, T *dst) const {
const int sz = m_size;
for (int i = 0; i < sz; ++i) {
dst[i] = src[i];
}
for (int i = 0; i < sz; ++i) {
dst[i] *= m_cache[i];
}
}
T getArea() { return m_area; }
T getValue(int i) { return m_cache[i]; }
WindowType getType() const { return m_type; }
int getSize() const { return m_size; }
protected:
WindowType m_type;
int m_size;
T *R__ 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

View File

@@ -1,76 +0,0 @@
/*
** Copyright (C) 2001 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
**
** Permission to use, copy, modify, distribute, and sell this file for any
** purpose is hereby granted without fee, provided that the above copyright
** and this permission notice appear in all copies. No representations are
** made about the suitability of this software for any purpose. It is
** provided "as is" without express or implied warranty.
*/
/* Version 1.1 */
/*============================================================================
** On Intel Pentium processors (especially PIII and probably P4), converting
** from float to int is very slow. To meet the C specs, the code produced by
** most C compilers targeting Pentium needs to change the FPU rounding mode
** before the float to int conversion is performed.
**
** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
** is this flushing of the pipeline which is so slow.
**
** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
** llrint and llrintf which fix this problem as a side effect.
**
** On Unix-like systems, the configure process should have detected the
** presence of these functions. If they weren't found we have to replace them
** here with a standard C cast.
*/
/*
** The C99 prototypes for lrint and lrintf are as follows:
**
** long int lrintf (float x) ;
** long int lrint (double x) ;
*/
#ifndef __FLOAT_CAST_H__ // Added by JE - 30-11-2009
#define __FLOAT_CAST_H__
#if (defined (WIN32) || defined (_WIN32))
#include <math.h>
/* Win32 doesn't seem to have these functions.
** Therefore implement inline versions of these functions here.
*/
__inline long int
lrint (double flt)
{ int intgr;
_asm
{ fld flt
fistp intgr
} ;
return intgr ;
}
__inline long int
lrintf (float flt)
{ int intgr;
_asm
{ fld flt
fistp intgr
} ;
return intgr ;
}
#endif
#endif // __FLOAT_CAST_H__

View File

@@ -1,112 +0,0 @@
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
getopt(nargc, nargv, ostr)
int nargc;
char * const *nargv;
const char *ostr;
{
static char *place = EMSG; /* option letter processing */
char *oli; /* option letter list index */
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc || *(place = nargv[optind]) != '-') {
place = EMSG;
return (-1);
}
if (place[1] && *++place == '-') { /* found "--" */
++optind;
place = EMSG;
return (-1);
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' ||
!(oli = strchr(ostr, optopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (optopt == (int)'-')
return (-1);
if (!*place)
++optind;
if (opterr && *ostr != ':' && optopt != BADCH)
(void)fprintf(stderr, "%s: illegal option -- %c\n",
"progname", optopt);
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
optarg = NULL;
if (!*place)
++optind;
}
else { /* need an argument */
if (*place) /* no white space */
optarg = place;
else if (nargc <= ++optind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)fprintf(stderr,
"%s: option requires an argument -- %c\n",
"progname", optopt);
return (BADCH);
}
else /* white space */
optarg = nargv[optind];
place = EMSG;
++optind;
}
return (optopt); /* dump back option letter */
}

View File

@@ -1,110 +0,0 @@
/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
/* $FreeBSD: src/include/getopt.h,v 1.1 2002/09/29 04:14:30 eric Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _GETOPT_H_
#define _GETOPT_H_
#ifdef _WIN32
/* from <sys/cdefs.h> */
# ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
# else
# define __BEGIN_DECLS
# define __END_DECLS
# endif
# define __P(args) args
#endif
/*#ifndef _WIN32
#include <sys/cdefs.h>
#include <unistd.h>
#endif*/
#ifdef _WIN32
# if !defined(GETOPT_API)
# define GETOPT_API __declspec(dllimport)
# endif
#endif
/*
* Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions
*/
#if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE)
#define no_argument 0
#define required_argument 1
#define optional_argument 2
struct option {
/* name of long option */
const char *name;
/*
* one of no_argument, required_argument, and optional_argument:
* whether option takes an argument
*/
int has_arg;
/* if not NULL, set *flag to val when option found */
int *flag;
/* if flag not NULL, value to set *flag to; else return value */
int val;
};
__BEGIN_DECLS
GETOPT_API int getopt_long __P((int, char * const *, const char *,
const struct option *, int *));
__END_DECLS
#endif
#ifdef _WIN32
/* These are global getopt variables */
__BEGIN_DECLS
GETOPT_API extern int opterr, /* if error message should be printed */
optind, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
GETOPT_API extern char* optarg; /* argument associated with option */
/* Original getopt */
GETOPT_API int getopt __P((int, char * const *, const char *));
__END_DECLS
#endif
#endif /* !_GETOPT_H_ */

View File

@@ -1,547 +0,0 @@
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/* $FreeBSD: src/lib/libc/stdlib/getopt_long.c,v 1.2 2002/10/16 22:18:42 alfred Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
/* Windows needs warnx(). We change the definition though:
* 1. (another) global is defined, opterrmsg, which holds the error message
* 2. errors are always printed out on stderr w/o the program name
* Note that opterrmsg always gets set no matter what opterr is set to. The
* error message will not be printed if opterr is 0 as usual.
*/
#include "getopt.h"
#include <stdio.h>
#include <stdarg.h>
GETOPT_API extern char opterrmsg[128];
char opterrmsg[128]; /* last error message is stored here */
static void warnx(int print_error, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (fmt != NULL)
_vsnprintf(opterrmsg, 128, fmt, ap);
else
opterrmsg[0]='\0';
va_end(ap);
if (print_error) {
fprintf(stderr, opterrmsg);
fprintf(stderr, "\n");
}
}
#endif /*_WIN32*/
/* not part of the original file */
#ifndef _DIAGASSERT
#define _DIAGASSERT(X)
#endif
#if HAVE_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND
#define REPLACE_GETOPT
#endif
#ifdef REPLACE_GETOPT
#ifdef __weak_alias
__weak_alias(getopt,_getopt)
#endif
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#elif HAVE_CONFIG_H && !HAVE_DECL_OPTRESET
static int optreset;
#endif
#ifdef __weak_alias
__weak_alias(getopt_long,_getopt_long)
#endif
#if !HAVE_GETOPT_LONG
#define IGNORE_FIRST (*options == '-' || *options == '+')
#define PRINT_ERROR ((opterr) && ((*options != ':') \
|| (IGNORE_FIRST && options[1] != ':')))
#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
/* XXX: GNU ignores PC if *options == '-' */
#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
/* return values */
#define BADCH (int)'?'
#define BADARG ((IGNORE_FIRST && options[1] == ':') \
|| (*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#define EMSG ""
static int getopt_internal(int, char * const *, const char *);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptchar[] = "unknown option -- %c";
static const char illoptstring[] = "unknown option -- %s";
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(a, b)
int a;
int b;
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return b;
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(panonopt_start, panonopt_end, opt_end, nargv)
int panonopt_start;
int panonopt_end;
int opt_end;
char * const *nargv;
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
_DIAGASSERT(nargv != NULL);
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
* Returns -2 if -- is found (can be long option or end of options marker).
*/
static int
getopt_internal(nargc, nargv, options)
int nargc;
char * const *nargv;
const char *options;
{
char *oli; /* option letter list index */
int optchar;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
optarg = NULL;
/*
* XXX Some programs (like rsyncd) expect to be able to
* XXX re-initialize optind to 0 and have getopt_long(3)
* XXX properly function again. Work around this braindamage.
*/
if (optind == 0)
optind = 1;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return -1;
}
if ((*(place = nargv[optind]) != '-')
|| (place[1] == '\0')) { /* found non-option */
place = EMSG;
if (IN_ORDER) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return INORDER;
}
if (!PERMUTE) {
/*
* if no permutation wanted, stop parsing
* at first non-option
*/
return -1;
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
if (place[1] && *++place == '-') { /* found "--" */
place++;
return -2;
}
}
if ((optchar = (int)*place++) == (int)':' ||
(oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
/* option letter unknown or ':' */
if (!*place)
++optind;
#ifndef _WIN32
if (PRINT_ERROR)
warnx(illoptchar, optchar);
#else
warnx(PRINT_ERROR, illoptchar, optchar);
#endif
optopt = optchar;
return BADCH;
}
if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
/* XXX: what if no long options provided (called by getopt)? */
if (*place)
return -2;
if (++optind >= nargc) { /* no arg */
place = EMSG;
#ifndef _WIN32
if (PRINT_ERROR)
warnx(recargchar, optchar);
#else
warnx(PRINT_ERROR, recargchar, optchar);
#endif
optopt = optchar;
return BADARG;
} else /* white space */
place = nargv[optind];
/*
* Handle -W arg the same as --arg (which causes getopt to
* stop parsing).
*/
return -2;
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
/* XXX: disable test for :: if PC? (GNU doesn't) */
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
#ifndef _WIN32
if (PRINT_ERROR)
warnx(recargchar, optchar);
#else
warnx(PRINT_ERROR, recargchar, optchar);
#endif
optopt = optchar;
return BADARG;
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return optchar;
}
#ifdef REPLACE_GETOPT
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the real getopt]
*/
int
getopt(nargc, nargv, options)
int nargc;
char * const *nargv;
const char *options;
{
int retval;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
++optind;
/*
* We found an option (--), so if we skipped non-options,
* we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end, optind,
nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
retval = -1;
}
return retval;
}
#endif
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(nargc, nargv, options, long_options, idx)
int nargc;
char * const *nargv;
const char *options;
const struct option *long_options;
int *idx;
{
int retval;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
_DIAGASSERT(long_options != NULL);
/* idx may be NULL */
if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
char *current_argv, *has_equal;
size_t current_argv_len;
int i, match;
current_argv = place;
match = -1;
optind++;
place = EMSG;
if (*current_argv == '\0') { /* found "--" */
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return -1;
}
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) ==
(unsigned)current_argv_len) {
/* exact match */
match = i;
break;
}
if (match == -1) /* partial match */
match = i;
else {
/* ambiguous abbreviation */
#ifndef _WIN32
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len,
current_argv);
#else
warnx(PRINT_ERROR, ambig, (int)current_argv_len,
current_argv);
#endif
optopt = 0;
return BADCH;
}
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
#ifndef _WIN32
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len,
current_argv);
#else
warnx(PRINT_ERROR, noarg, (int)current_argv_len,
current_argv);
#endif
/*
* XXX: GNU sets optopt to val regardless of
* flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return BADARG;
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use
* next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':'
* indicates no error should be generated
*/
#ifndef _WIN32
if (PRINT_ERROR)
warnx(recargstring, current_argv);
#else
warnx(PRINT_ERROR, recargstring, current_argv);
#endif
/*
* XXX: GNU sets optopt to val regardless
* of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return BADARG;
}
} else { /* unknown option */
#ifndef _WIN32
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
#else
warnx(PRINT_ERROR, illoptstring, current_argv);
#endif
optopt = 0;
return BADCH;
}
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
retval = 0;
} else
retval = long_options[match].val;
if (idx)
*idx = match;
}
return retval;
}
#endif /* !GETOPT_LONG */

View File

@@ -1,554 +0,0 @@
/* -*- 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-2008 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;
using std::cout;
using std::cerr;
using std::endl;
using std::min;
const char *const
RubberBandPitchShifter::portNamesMono[PortCountMono] =
{
"latency",
"Cents",
"Semitones",
"Octaves",
"Crispness",
"Formant Preserving",
"Faster",
"Input",
"Output"
};
const char *const
RubberBandPitchShifter::portNamesStereo[PortCountStereo] =
{
"latency",
"Cents",
"Semitones",
"Octaves",
"Crispness",
"Formant Preserving",
"Faster",
"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_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_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 }, // latency
{ LADSPA_HINT_DEFAULT_0 | // cents
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE,
-100.0, 100.0 },
{ LADSPA_HINT_DEFAULT_0 | // semitones
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-12.0, 12.0 },
{ LADSPA_HINT_DEFAULT_0 | // octaves
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-3.0, 3.0 },
{ LADSPA_HINT_DEFAULT_MAXIMUM | // crispness
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
0.0, 3.0 },
{ LADSPA_HINT_DEFAULT_0 | // formant preserving
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ LADSPA_HINT_DEFAULT_0 | // fast
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ 0, 0, 0 },
{ 0, 0, 0 }
};
const LADSPA_PortRangeHint
RubberBandPitchShifter::hintsStereo[PortCountStereo] =
{
{ 0, 0, 0 }, // latency
{ LADSPA_HINT_DEFAULT_0 | // cents
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE,
-100.0, 100.0 },
{ LADSPA_HINT_DEFAULT_0 | // semitones
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-12.0, 12.0 },
{ LADSPA_HINT_DEFAULT_0 | // octaves
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-3.0, 3.0 },
{ LADSPA_HINT_DEFAULT_MAXIMUM | // crispness
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
0.0, 3.0 },
{ LADSPA_HINT_DEFAULT_0 | // formant preserving
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ LADSPA_HINT_DEFAULT_0 | // fast
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.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
"Breakfast Quay",
"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
"Breakfast Quay",
"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_formant(0),
m_fast(0),
m_ratio(1.0),
m_prevRatio(1.0),
m_currentCrispness(-1),
m_currentFormant(false),
m_currentFast(false),
m_blockSize(1024),
m_reserve(1024),
m_minfill(0),
m_stretcher(new RubberBandStretcher
(sampleRate, channels,
RubberBandStretcher::OptionProcessRealTime |
RubberBandStretcher::OptionPitchHighConsistency)),
m_sampleRate(sampleRate),
m_channels(channels)
{
for (size_t c = 0; c < m_channels; ++c) {
m_input[c] = 0;
m_output[c] = 0;
int bufsize = m_blockSize + m_reserve + 8192;
m_outputBuffer[c] = new RingBuffer<float>(bufsize);
m_scratch[c] = new float[bufsize];
for (int i = 0; i < bufsize; ++i) m_scratch[c][i] = 0.f;
}
activateImpl();
}
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_formant,
&shifter->m_fast,
&shifter->m_input[0],
&shifter->m_output[0],
&shifter->m_input[1],
&shifter->m_output[1]
};
if (shifter->m_channels == 1) {
if (port >= PortCountMono) return;
} else {
if (port >= PortCountStereo) return;
}
*ports[port] = (float *)location;
if (shifter->m_latency) {
*(shifter->m_latency) =
float(shifter->m_stretcher->getLatency() + shifter->m_reserve);
}
}
void
RubberBandPitchShifter::activate(LADSPA_Handle handle)
{
RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
shifter->activateImpl();
}
void
RubberBandPitchShifter::activateImpl()
{
updateRatio();
m_prevRatio = m_ratio;
m_stretcher->reset();
m_stretcher->setPitchScale(m_ratio);
for (size_t c = 0; c < m_channels; ++c) {
m_outputBuffer[c]->reset();
m_outputBuffer[c]->zero(m_reserve);
}
m_minfill = 0;
// prime stretcher
// for (int i = 0; i < 8; ++i) {
// int reqd = m_stretcher->getSamplesRequired();
// m_stretcher->process(m_scratch, reqd, false);
// int avail = m_stretcher->available();
// if (avail > 0) {
// m_stretcher->retrieve(m_scratch, avail);
// }
// }
}
void
RubberBandPitchShifter::run(LADSPA_Handle handle, unsigned long samples)
{
RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
shifter->runImpl(samples);
}
void
RubberBandPitchShifter::updateRatio()
{
double oct = (m_octaves ? *m_octaves : 0.0);
oct += (m_semitones ? *m_semitones : 0.0) / 12;
oct += (m_cents ? *m_cents : 0.0) / 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::OptionPhaseLaminar);
s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth);
break;
case 2:
s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
s->setTransientsOption(RubberBandStretcher::OptionTransientsMixed);
break;
case 3:
s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
s->setTransientsOption(RubberBandStretcher::OptionTransientsCrisp);
break;
}
m_currentCrispness = c;
}
void
RubberBandPitchShifter::updateFormant()
{
if (!m_formant) return;
bool f = (*m_formant > 0.5f);
if (f == m_currentFormant) return;
RubberBandStretcher *s = m_stretcher;
s->setFormantOption(f ?
RubberBandStretcher::OptionFormantPreserved :
RubberBandStretcher::OptionFormantShifted);
m_currentFormant = f;
}
void
RubberBandPitchShifter::updateFast()
{
if (!m_fast) return;
bool f = (*m_fast > 0.5f);
if (f == m_currentFast) return;
RubberBandStretcher *s = m_stretcher;
s->setPitchOption(f ?
RubberBandStretcher::OptionPitchHighSpeed :
RubberBandStretcher::OptionPitchHighConsistency);
m_currentFast = f;
}
void
RubberBandPitchShifter::runImpl(unsigned long insamples)
{
unsigned long offset = 0;
// We have to break up the input into chunks like this because
// insamples could be arbitrarily large and our output buffer is
// of limited size
while (offset < insamples) {
unsigned long block = (unsigned long)m_blockSize;
if (block + offset > insamples) block = insamples - offset;
runImpl(block, offset);
offset += block;
}
}
void
RubberBandPitchShifter::runImpl(unsigned long insamples, unsigned long offset)
{
// cerr << "RubberBandPitchShifter::runImpl(" << insamples << ")" << endl;
// static int incount = 0, outcount = 0;
updateRatio();
if (m_ratio != m_prevRatio) {
m_stretcher->setPitchScale(m_ratio);
m_prevRatio = m_ratio;
}
if (m_latency) {
*m_latency = float(m_stretcher->getLatency() + m_reserve);
// cerr << "latency = " << *m_latency << endl;
}
updateCrispness();
updateFormant();
updateFast();
const int samples = insamples;
int processed = 0;
size_t outTotal = 0;
float *ptrs[2];
int rs = m_outputBuffer[0]->getReadSpace();
if (rs < int(m_minfill)) {
// cerr << "temporary expansion (have " << rs << ", want " << m_reserve << ")" << endl;
m_stretcher->setTimeRatio(1.1); // fill up temporarily
} else if (rs > 8192) {
// cerr << "temporary reduction (have " << rs << ", want " << m_reserve << ")" << endl;
m_stretcher->setTimeRatio(0.9); // reduce temporarily
} else {
m_stretcher->setTimeRatio(1.0);
}
while (processed < samples) {
// never feed more than the minimum necessary number of
// samples at a time; ensures nothing will overflow internally
// and we don't need to call setMaxProcessSize
int toCauseProcessing = m_stretcher->getSamplesRequired();
int inchunk = min(samples - processed, toCauseProcessing);
for (size_t c = 0; c < m_channels; ++c) {
ptrs[c] = &(m_input[c][offset + processed]);
}
m_stretcher->process(ptrs, inchunk, false);
processed += inchunk;
int avail = m_stretcher->available();
int writable = m_outputBuffer[0]->getWriteSpace();
int outchunk = min(avail, writable);
size_t actual = m_stretcher->retrieve(m_scratch, outchunk);
outTotal += actual;
// incount += inchunk;
// outcount += actual;
// cout << "avail: " << avail << ", outchunk = " << outchunk;
// if (actual != outchunk) cout << " (" << actual << ")";
// cout << endl;
outchunk = actual;
for (size_t c = 0; c < m_channels; ++c) {
if (int(m_outputBuffer[c]->getWriteSpace()) < outchunk) {
cerr << "RubberBandPitchShifter::runImpl: buffer overrun: chunk = " << outchunk << ", space = " << m_outputBuffer[c]->getWriteSpace() << endl;
}
m_outputBuffer[c]->write(m_scratch[c], outchunk);
}
}
for (size_t c = 0; c < m_channels; ++c) {
int toRead = m_outputBuffer[c]->getReadSpace();
if (toRead < samples && c == 0) {
cerr << "RubberBandPitchShifter::runImpl: buffer underrun: required = " << samples << ", available = " << toRead << endl;
}
int chunk = min(toRead, samples);
m_outputBuffer[c]->read(&(m_output[c][offset]), chunk);
}
if (m_minfill == 0) {
m_minfill = m_outputBuffer[0]->getReadSpace();
// cerr << "minfill = " << m_minfill << endl;
}
}
void
RubberBandPitchShifter::deactivate(LADSPA_Handle handle)
{
activate(handle); // both functions just reset the plugin
}
void
RubberBandPitchShifter::cleanup(LADSPA_Handle handle)
{
delete (RubberBandPitchShifter *)handle;
}

View File

@@ -1,107 +0,0 @@
/* -*- 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-2008 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,
FormantPort = 5,
FastPort = 6,
InputPort1 = 7,
OutputPort1 = 8,
PortCountMono = OutputPort1 + 1,
InputPort2 = 9,
OutputPort2 = 10,
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 activateImpl();
void runImpl(unsigned long);
void runImpl(unsigned long, unsigned long offset);
void updateRatio();
void updateCrispness();
void updateFormant();
void updateFast();
float *m_input[2];
float *m_output[2];
float *m_latency;
float *m_cents;
float *m_semitones;
float *m_octaves;
float *m_crispness;
float *m_formant;
float *m_fast;
double m_ratio;
double m_prevRatio;
int m_currentCrispness;
bool m_currentFormant;
bool m_currentFast;
size_t m_blockSize;
size_t m_reserve;
size_t m_minfill;
RubberBand::RubberBandStretcher *m_stretcher;
RubberBand::RingBuffer<float> *m_outputBuffer[2];
float *m_scratch[2];
int m_sampleRate;
size_t m_channels;
};
#endif

View File

@@ -1,2 +0,0 @@
ladspa:ladspa-rubberband:rubberband-pitchshifter-mono::Frequency > Pitch shifters
ladspa:ladspa-rubberband:rubberband-pitchshifter-stereo::Frequency > Pitch shifters

View File

@@ -1,26 +0,0 @@
/* -*- 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-2008 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);
}
}

View File

@@ -1,535 +0,0 @@
/* -*- 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-2008 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 <cstring>
#include <iostream>
#include <sndfile.h>
#include <cmath>
#include <time.h>
#include <cstdlib>
#include <cstring>
#include "sysutils.h"
#ifdef COMPILER_MSVC
#include "bsd-3rdparty/getopt/getopt.h"
#else
#include <getopt.h>
#include <sys/time.h>
#include <unistd.h>
#endif
#include "Profiler.h"
using namespace std;
using namespace RubberBand;
#ifdef PLATFORM_WINDOWS
using RubberBand::gettimeofday;
using RubberBand::usleep;
#endif
double tempo_convert(const char *str)
{
const char *d = strchr(str, ':');
if (!d || !*d) {
double m = atof(str);
if (m != 0.0) return 1.0 / m;
else return 1.0;
}
char *a = strdup(str);
char *b = strdup(d+1);
a[d-str] = '\0';
double m = atof(a);
double n = atof(b);
free(a);
free(b);
if (n != 0.0 && m != 0.0) return m / n;
else return 1.0;
}
int main(int argc, char **argv)
{
int c;
double ratio = 1.0;
double duration = 0.0;
double pitchshift = 0.0;
double frequencyshift = 1.0;
int debug = 0;
bool realtime = false;
bool precise = false;
int threading = 0;
bool lamination = true;
bool longwin = false;
bool shortwin = false;
bool hqpitch = false;
bool formant = false;
bool crispchanged = false;
int crispness = -1;
bool help = false;
bool version = false;
bool quiet = false;
bool haveRatio = false;
enum {
NoTransients,
BandLimitedTransients,
Transients
} transients = Transients;
while (1) {
int optionIndex = 0;
static struct option longOpts[] = {
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'V' },
{ "time", 1, 0, 't' },
{ "tempo", 1, 0, 'T' },
{ "duration", 1, 0, 'D' },
{ "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' },
{ "formant", 0, 0, 'F' },
{ "no-threads", 0, 0, '0' },
{ "no-transients", 0, 0, '1' },
{ "no-lamination", 0, 0, '2' },
{ "window-long", 0, 0, '3' },
{ "window-short", 0, 0, '4' },
{ "bl-transients", 0, 0, '8' },
{ "pitch-hq", 0, 0, '%' },
{ "threads", 0, 0, '@' },
{ "quiet", 0, 0, 'q' },
{ 0, 0, 0, '\0' }
};
c = getopt_long(argc, argv, "t:p:d:RPFc:f:T:D:qhV", longOpts, &optionIndex);
if (c == -1) break;
switch (c) {
case 'h': help = true; break;
case 'V': version = true; break;
case 't': ratio *= atof(optarg); haveRatio = true; break;
case 'T': ratio *= tempo_convert(optarg); haveRatio = true; break;
case 'D': duration = atof(optarg); 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 'F': formant = true; break;
case '0': threading = 1; break;
case '@': threading = 2; break;
case '1': transients = NoTransients; crispchanged = true; break;
case '2': lamination = false; crispchanged = true; break;
case '3': longwin = true; crispchanged = true; break;
case '4': shortwin = true; crispchanged = true; break;
case '8': transients = BandLimitedTransients; crispchanged = true; break;
case '%': hqpitch = true; break;
case 'c': crispness = atoi(optarg); break;
case 'q': quiet = true; break;
default: help = true; break;
}
}
if (version) {
cerr << RUBBERBAND_VERSION << endl;
return 0;
}
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 2008 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 (same as --time 1/X), or" << endl;
cerr << " -T<X>, --tempo <X>:<Y> Change tempo from X to Y (same as --time X/Y), or" << endl;
cerr << " -D<X>, --duration <X> Stretch or squash to make output file X seconds long" << 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 options provide 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 << " -F, --formant Enable formant preservation when pitch shifting" << 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. The default is to use none of these options." << 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-lamination Disable phase lamination" << endl;
cerr << " --window-long Use longer processing window (actual size may vary)" << endl;
cerr << " --window-short Use shorter processing window" << endl;
cerr << " --pitch-hq In RT mode, use a slower, higher quality pitch shift" << 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 << " -V, --version Show version number and exit" << endl;
cerr << " -h, --help Show this help" << endl;
cerr << endl;
cerr << "\"Crispness\" levels:" << endl;
cerr << " -c 0 equivalent to --no-transients --no-lamination --window-long" << endl;
cerr << " -c 1 equivalent to --no-transients --no-lamination" << 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-lamination --window-short (may be good for drums)" << endl;
cerr << endl;
return 2;
}
if (crispness >= 0 && crispchanged) {
cerr << "WARNING: Both crispness option and transients, lamination or window options" << endl;
cerr << " provided -- crispness will override these other options" << endl;
}
switch (crispness) {
case -1: crispness = 4; break;
case 0: transients = NoTransients; lamination = false; longwin = true; shortwin = false; break;
case 1: transients = NoTransients; lamination = false; longwin = false; shortwin = false; break;
case 2: transients = NoTransients; lamination = true; longwin = false; shortwin = false; break;
case 3: transients = BandLimitedTransients; lamination = true; longwin = false; shortwin = false; break;
case 4: transients = Transients; lamination = true; longwin = false; shortwin = false; break;
case 5: transients = Transients; lamination = 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;
}
if (duration != 0.0) {
if (sfinfo.frames == 0 || sfinfo.samplerate == 0) {
cerr << "ERROR: File lacks frame count or sample rate in header, cannot use --duration" << endl;
return 1;
}
double induration = double(sfinfo.frames) / double(sfinfo.samplerate);
if (induration != 0.0) ratio = duration / induration;
}
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 \"" << fileNameOut << "\" for writing: "
<< sf_strerror(sndfileOut) << 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 (!lamination) options |= RubberBandStretcher::OptionPhaseIndependent;
if (longwin) options |= RubberBandStretcher::OptionWindowLong;
if (shortwin) options |= RubberBandStretcher::OptionWindowShort;
if (formant) options |= RubberBandStretcher::OptionFormantPreserved;
if (hqpitch) options |= RubberBandStretcher::OptionPitchHighQuality;
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 != 0.0) {
frequencyshift *= pow(2.0, pitchshift / 12);
}
cerr << "Using time ratio " << ratio;
cerr << " and frequency ratio " << frequencyshift << endl;
#ifdef PLATFORM_WINDOWS
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 {
#ifdef PLATFORM_WINDOWS
RubberBand::usleep(10000);
#else
usleep(10000);
#endif
}
}
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 PLATFORM_WINDOWS
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;
}
Profiler::dump();
return 0;
}

View File

@@ -1,146 +0,0 @@
/* -*- 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-2008 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 "rubberband-c.h"
#include "RubberBandStretcher.h"
struct RubberBandState_
{
RubberBand::RubberBandStretcher *m_s;
};
RubberBandState rubberband_new(unsigned int sampleRate,
unsigned int channels,
RubberBandOptions options,
double initialTimeRatio,
double initialPitchScale)
{
RubberBandState_ *state = new RubberBandState_();
state->m_s = new RubberBand::RubberBandStretcher
(sampleRate, channels, options,
initialTimeRatio, initialPitchScale);
return state;
}
void rubberband_delete(RubberBandState state)
{
delete state->m_s;
delete state;
}
void rubberband_reset(RubberBandState state)
{
state->m_s->reset();
}
void rubberband_set_time_ratio(RubberBandState state, double ratio)
{
state->m_s->setTimeRatio(ratio);
}
void rubberband_set_pitch_scale(RubberBandState state, double scale)
{
state->m_s->setPitchScale(scale);
}
double rubberband_get_time_ratio(const RubberBandState state)
{
return state->m_s->getTimeRatio();
}
double rubberband_get_pitch_scale(const RubberBandState state)
{
return state->m_s->getPitchScale();
}
unsigned int rubberband_get_latency(const RubberBandState state)
{
return state->m_s->getLatency();
}
void rubberband_set_transients_option(RubberBandState state, RubberBandOptions options)
{
state->m_s->setTransientsOption(options);
}
void rubberband_set_phase_option(RubberBandState state, RubberBandOptions options)
{
state->m_s->setPhaseOption(options);
}
void rubberband_set_formant_option(RubberBandState state, RubberBandOptions options)
{
state->m_s->setFormantOption(options);
}
void rubberband_set_pitch_option(RubberBandState state, RubberBandOptions options)
{
state->m_s->setPitchOption(options);
}
void rubberband_set_expected_input_duration(RubberBandState state, unsigned int samples)
{
state->m_s->setExpectedInputDuration(samples);
}
unsigned int rubberband_get_samples_required(const RubberBandState state)
{
return state->m_s->getSamplesRequired();
}
void rubberband_set_max_process_size(RubberBandState state, unsigned int samples)
{
state->m_s->setMaxProcessSize(samples);
}
void rubberband_study(RubberBandState state, const float *const *input, unsigned int samples, int final)
{
state->m_s->study(input, samples, final != 0);
}
void rubberband_process(RubberBandState state, const float *const *input, unsigned int samples, int final)
{
state->m_s->process(input, samples, final != 0);
}
int rubberband_available(const RubberBandState state)
{
return state->m_s->available();
}
unsigned int rubberband_retrieve(const RubberBandState state, float *const *output, unsigned int samples)
{
return state->m_s->retrieve(output, samples);
}
unsigned int rubberband_get_channel_count(const RubberBandState state)
{
return state->m_s->getChannelCount();
}
void rubberband_calculate_stretch(RubberBandState state)
{
state->m_s->calculateStretch();
}
void rubberband_set_debug_level(RubberBandState state, int level)
{
state->m_s->setDebugLevel(level);
}
void rubberband_set_default_debug_level(int level)
{
RubberBand::RubberBandStretcher::setDefaultDebugLevel(level);
}

View File

@@ -1,158 +0,0 @@
/* -*- 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-2008 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 <cstdio>
#include <cstring>
#endif /* !__APPLE__, !_WIN32 */
#endif /* !_WIN32 */
#include <cstdlib>
#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
int 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);
return 0;
}
void usleep(unsigned long usec)
{
::Sleep(usec == 0 ? 0 : usec < 1000 ? 1 : usec / 1000);
}
#endif
float *allocFloat(float *ptr, int count)
{
if (ptr) free((void *)ptr);
void *allocated;
#ifndef _WIN32
#ifndef __APPLE__
if (posix_memalign(&allocated, 16, count * sizeof(float)))
#endif
#endif
allocated = malloc(count * sizeof(float));
for (int i = 0; i < count; ++i) ((float *)allocated)[i] = 0.f;
return (float *)allocated;
}
float *allocFloat(int count)
{
return allocFloat(0, count);
}
void freeFloat(float *ptr)
{
if (ptr) free(ptr);
}
double *allocDouble(double *ptr, int count)
{
if (ptr) free((void *)ptr);
void *allocated;
#ifndef _WIN32
#ifndef __APPLE__
if (posix_memalign(&allocated, 16, count * sizeof(double)))
#endif
#endif
allocated = malloc(count * sizeof(double));
for (int i = 0; i < count; ++i) ((double *)allocated)[i] = 0.f;
return (double *)allocated;
}
double *allocDouble(int count)
{
return allocDouble(0, count);
}
void freeDouble(double *ptr)
{
if (ptr) free(ptr);
}
}

View File

@@ -1,62 +0,0 @@
/* -*- 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-2008 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_
#ifdef COMPILER_MSVC
#include "bsd-3rdparty/float_cast/float_cast.h"
#define R__ __restrict
#endif
#ifdef __GNUC__
#define R__ __restrict__
#endif
#ifndef R__
#define R__
#endif
#ifdef COMPILER_MINGW
#include <malloc.h>
#endif
#ifdef COMPILER_MSVC
#define alloca _alloca
#endif
namespace RubberBand {
extern bool system_is_multiprocessor();
#ifdef _WIN32
struct timeval { long tv_sec; long tv_usec; };
int gettimeofday(struct timeval *p, void *tz);
void usleep(unsigned long);
#endif
extern float *allocFloat(int);
extern float *allocFloat(float *, int);
extern void freeFloat(float *);
extern double *allocDouble(int);
extern double *allocDouble(double *, int);
extern void freeDouble(double *);
}
#endif

View File

@@ -1,648 +0,0 @@
/* -*- 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-2008 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 "sysutils.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 "Breakfast Quay";
}
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 = float(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 = float(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.f : 0.f;
if (id == "stretchtype") return m_d->m_elasticTiming ? 0.f : 1.f;
if (id == "transientmode") return float(m_d->m_transientMode);
if (id == "phasemode") return m_d->m_phaseIndependent ? 1.f : 0.f;
if (id == "windowmode") return float(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::OptionPhaseLaminar;
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(float(oi));
feature.label = Vamp::RealTime::frame2RealTime(oi, rate).toText();
features[m_incrementsOutput].push_back(feature);
feature.values.clear();
feature.values.push_back(float(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", int(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(float(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;
}

View File

@@ -1,56 +0,0 @@
/* -*- 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-2008 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

View File

@@ -1,32 +0,0 @@
/* -*- 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-2008 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;
}
}

View File

@@ -1 +0,0 @@
vamp:vamp-rubberband:rubberband::Time > Timestretch Analysis

View File

@@ -1,55 +0,0 @@
#!/usr/bin/env python
from waflib.extras import autowaf as autowaf
import os
import glob
# Version of this package (even if built as a child)
LIBRUBBERBAND_VERSION = '0.0.0'
# Library version (UNIX style major, minor, micro)
# major increment <=> incompatible changes
# minor increment <=> compatible changes (additions)
# micro increment <=> no interface changes
LIBRUBBERBAND_LIB_VERSION = '4.1.0'
# Variables for 'waf dist'
APPNAME = 'librubberband'
VERSION = LIBRUBBERBAND_VERSION
# Mandatory variables
top = '.'
out = 'build'
def options(opt):
autowaf.set_options(opt)
def configure(conf):
if conf.is_defined('USE_EXTERNAL_LIBS'):
autowaf.check_pkg(conf, 'rubberband', uselib_store='RUBBERBAND', atleast_version='1.0', mandatory=True)
else:
conf.load('compiler_cxx')
autowaf.configure(conf)
def build(bld):
if bld.is_defined('USE_EXTERNAL_LIBS'):
return
# Library
obj = bld(features = 'cxx cxxshlib')
prefix = 'libs/rubberband/'
sources = glob.glob(prefix + 'src/*.cpp')
obj.source = [ ]
for i in sources:
obj.source += [ i.replace(prefix, '') ]
obj.export_includes = ['.']
obj.includes = ['.', 'rubberband']
obj.name = 'librubberband'
obj.target = 'rubberband'
obj.uselib = 'FFTW3 FFTW3F SAMPLERATE SNDFILE'
obj.use = 'libvamphost'
obj.vnum = LIBRUBBERBAND_LIB_VERSION
obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
obj.cxxflags = '-DPACKAGE="librubberband"'
def shutdown():
autowaf.shutdown()

View File

@@ -1,26 +0,0 @@
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.

View File

@@ -1,240 +0,0 @@
Vamp
====
An API for audio analysis and feature extraction plugins.
http://www.vamp-plugins.org/
Vamp is an API for C and C++ plugins that process sampled audio data
to produce descriptive output (measurements or semantic observations).
The principal differences between Vamp and a real-time audio
processing plugin system such as VST are:
* Vamp plugins may output complex multidimensional data with labels.
As a consequence, they are likely to work best when the output
data has a much lower sampling rate than the input. (This also
means it is usually desirable to implement them in C++ using the
high-level base class provided rather than use the raw C API.)
* While Vamp plugins receive data block-by-block, they are not
required to return output immediately on receiving the input.
A Vamp plugin may be non-causal, preferring to store up data
based on its input until the end of a processing run and then
return all results at once.
* Vamp plugins have more control over their inputs than a typical
real-time processing plugin. For example, they can indicate to
the host their preferred processing block and step sizes, and these
may differ.
* Vamp plugins may ask to receive data in the frequency domain
instead of the time domain. The host takes the responsibility
for converting the input data using an FFT of windowed frames.
This simplifies plugins that do straightforward frequency-domain
processing and permits the host to cache frequency-domain data
when possible.
* A Vamp plugin is configured once before each processing run, and
receives no further parameter changes during use -- unlike real-
time plugin APIs in which the input parameters may change at any
time. This also means that fundamental properties such as the
number of values per output or the preferred processing block
size may depend on the input parameters.
* Vamp plugins do not have to be able to run in real time.
About this SDK
==============
This is version 1.1b of the Vamp plugin Software Development Kit.
Plugins and hosts built with this SDK are binary compatible with those
built using version 1.0 of the SDK.
This SDK contains the following:
* vamp/vamp.h
The formal C language plugin API for Vamp plugins.
A Vamp plugin is a dynamic library (.so, .dll or .dylib depending on
platform) exposing one C-linkage entry point (vampGetPluginDescriptor)
which returns data defined in the rest of this C header.
Although the C API is the official API for Vamp, we don't recommend
that you program directly to it. The C++ abstraction found in the
vamp-sdk directory (below) is preferable for most purposes and is
more thoroughly documented.
* vamp-sdk
C++ classes for straightforwardly implementing Vamp plugins and hosts.
Plugins should subclass Vamp::Plugin and then use Vamp::PluginAdapter
to expose the correct C API for the plugin. Plugin authors should
read vamp-sdk/PluginBase.h and Plugin.h for code documentation, and
refer to the example plugin code in the examples directory. Plugins
should link with -lvampsdk. [*NOTE: this has changed from vamp-sdk in
previous versions, to avoid conflict with the use of hyphens for
library versioning schemes on some platforms.]
Hosts may use the Vamp::PluginHostAdapter to convert the loaded
plugin's C API back into a Vamp::Plugin object. Host authors should
refer to the example host code in the host directory. Hosts should
link with -lvamphostsdk. [*NOTE: this has changed from vamp-hostsdk
in previous versions, to avoid conflict with the use of hyphens for
library versioning schemes on some platforms.]
* vamp-sdk/hostext
Additional C++ classes to make a host's life easier (introduced in
version 1.1 of the Vamp SDK).
Vamp::HostExt::PluginLoader provides a very easy interface for a host
to discover, load, and find out category information about the
available plugins. Most "casual" Vamp hosts will probably want to use
this class.
Vamp::HostExt::PluginInputDomainAdapter provides a means for hosts to
handle plugins that expect frequency-domain input, without having to
convert the input themselves.
Vamp::HostExt::PluginChannelAdapter provides a means for hosts to use
plugins that do not necessarily support the same number of audio
channels as they have available, without having to worry about
applying a channel management / mixdown policy themselves.
The PluginLoader class can also use the input domain and channel
adapters automatically to make the entire conversion process
transparent to the host if required.
* examples
Example plugins implemented using the C++ classes. ZeroCrossing
calculates the positions and density of zero-crossing points in an
audio waveform. SpectralCentroid calculates the centre of gravity of
the frequency domain representation of each block of audio.
AmplitudeFollower tracks the amplitude of a signal based on a method
from the SuperCollider real-time audio system.
PercussionOnsetDetector estimates the locations of percussive onsets
using a simple method described in "Drum Source Separation using
Percussive Feature Detection and Spectral Modulation" by Dan Barry,
Derry Fitzgerald, Eugene Coyle and Bob Lawlor, ISSC 2005.
* host
A simple command-line Vamp host, capable of loading a plugin and using
it to process a complete audio file, with its default parameters.
Requires libsndfile (http://www.mega-nerd.com/libsndfile/).
If you don't have libsndfile, you may want to edit the Makefile to
change the default build target from "all" to "sdk", so as to compile
only the SDK and not the host.
Plugin Lookup and Categorisation
================================
The Vamp API does not officially specify how to load plugin libraries
or where to find them. However, the SDK does include a function
(Vamp::PluginHostAdapter::getPluginPath()) that returns a recommended
directory search path that hosts may use for plugin libraries, and a
class (Vamp::HostExt::PluginLoader) that implements a sensible
cross-platform lookup policy using this path. We recommend using this
class in your host unless you have a good reason not to want to. This
implementation also permits the user to set the environment variable
VAMP_PATH to override the default path if desired.
The policy used by Vamp::HostExt::PluginLoader -- and our
recommendation for any host -- is to search each directory in the path
returned by getPluginPath for .DLL (on Windows), .so (on Linux,
Solaris, BSD etc) or .dylib (on OS/X) files, then to load each one and
perform a dynamic name lookup on the vampGetPluginDescriptor function
to enumerate the plugins in the library. This operation will
necessarily be system-dependent.
Vamp also has an informal convention for sorting plugins into
functional categories. In addition to the library file itself, a
plugin library may install a category file with the same name as the
library but .cat extension. The existence and format of this file are
not specified by the Vamp API, but by convention the file may contain
lines of the format
vamp:pluginlibrary:pluginname::General Category > Specific Category
which a host may read and use to assign plugins a location within a
category tree for display to the user. The expectation is that
advanced users may also choose to set up their own preferred category
trees, which is why this information is not queried as part of the
Vamp plugin's API itself. The Vamp::HostExt::PluginLoader class also
provides support for plugin category lookup using this scheme.
Building and Installing the SDK and Examples
============================================
To build the SDK, the simple host, and the example plugins, edit the
Makefile to suit your platform according to the comments in it, then
run "make".
To use an IDE to build a plugin or host using the Vamp SDK, simply add
the .cpp files in the vamp-sdk directory to your project.
Installing the example plugins so that they can be found by other Vamp
hosts depends on your platform:
* Windows: copy the files
examples/vamp-example-plugins.dll
examples/vamp-example-plugins.cat
to
C:\Program Files\Vamp Plugins
* Linux: copy the files
examples/vamp-example-plugins.so
examples/vamp-example-plugins.cat
to
/usr/local/lib/vamp/
* OS/X: copy the files
examples/vamp-example-plugins.dylib
examples/vamp-example-plugins.cat
to
/Library/Audio/Plug-Ins/Vamp
Licensing
=========
This plugin SDK is freely redistributable under a "new-style BSD"
licence. See the file COPYING for more details. In short, you may
modify and redistribute the SDK and example plugins within any
commercial or non-commercial, proprietary or open-source plugin or
application under almost any conditions, with no obligation to provide
source code, provided you retain the original copyright note.
See Also
========
Sonic Visualiser, an interactive open-source graphical audio
inspection, analysis and visualisation tool supporting Vamp plugins.
http://www.sonicvisualiser.org/
Authors
=======
Vamp and the Vamp SDK were designed and made at the Centre for Digital
Music at Queen Mary, University of London.
The SDK was written by Chris Cannam, copyright (c) 2005-2007
Chris Cannam and QMUL.
Mark Sandler and Christian Landone provided ideas and direction, and
Mark Levy, Dan Stowell, Martin Gasser and Craig Sapp provided testing
and other input for the 1.0 API and SDK. The API also uses some ideas
from prior plugin systems, notably DSSI (http://dssi.sourceforge.net)
and FEAPI (http://feapi.sourceforge.net).

View File

@@ -1,721 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2009 Chris Cannam and QMUL.
This file by Mark Levy and Chris Cannam, Copyright 2007-2009 QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include <vector>
#include <map>
#include "vamp-hostsdk/PluginBufferingAdapter.h"
#include "vamp-hostsdk/PluginInputDomainAdapter.h"
using std::vector;
using std::map;
_VAMP_SDK_HOSTSPACE_BEGIN(PluginBufferingAdapter.cpp)
namespace Vamp {
namespace HostExt {
class PluginBufferingAdapter::Impl
{
public:
Impl(Plugin *plugin, float inputSampleRate);
~Impl();
void setPluginStepSize(size_t stepSize);
void setPluginBlockSize(size_t blockSize);
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
OutputList getOutputDescriptors() const;
void setParameter(std::string, float);
void selectProgram(std::string);
void reset();
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures();
protected:
class RingBuffer
{
public:
RingBuffer(int n) :
m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { }
virtual ~RingBuffer() { delete[] m_buffer; }
int getSize() const { return m_size-1; }
void reset() { m_writer = 0; m_reader = 0; }
int getReadSpace() const {
int writer = m_writer, reader = m_reader, space;
if (writer > reader) space = writer - reader;
else if (writer < reader) space = (writer + m_size) - reader;
else space = 0;
return space;
}
int getWriteSpace() const {
int writer = m_writer;
int reader = m_reader;
int space = (reader + m_size - writer - 1);
if (space >= m_size) space -= m_size;
return space;
}
int peek(float *destination, int n) const {
int available = getReadSpace();
if (n > available) {
for (int i = available; i < n; ++i) {
destination[i] = 0.f;
}
n = available;
}
if (n == 0) return n;
int reader = m_reader;
int here = m_size - reader;
const float *const bufbase = m_buffer + reader;
if (here >= n) {
for (int i = 0; i < n; ++i) {
destination[i] = bufbase[i];
}
} else {
for (int i = 0; i < here; ++i) {
destination[i] = bufbase[i];
}
float *const destbase = destination + here;
const int nh = n - here;
for (int i = 0; i < nh; ++i) {
destbase[i] = m_buffer[i];
}
}
return n;
}
int skip(int n) {
int available = getReadSpace();
if (n > available) {
n = available;
}
if (n == 0) return n;
int reader = m_reader;
reader += n;
while (reader >= m_size) reader -= m_size;
m_reader = reader;
return n;
}
int write(const float *source, int n) {
int available = getWriteSpace();
if (n > available) {
n = available;
}
if (n == 0) return n;
int writer = m_writer;
int here = m_size - writer;
float *const bufbase = m_buffer + writer;
if (here >= n) {
for (int i = 0; i < n; ++i) {
bufbase[i] = source[i];
}
} else {
for (int i = 0; i < here; ++i) {
bufbase[i] = source[i];
}
const int nh = n - here;
const float *const srcbase = source + here;
float *const buf = m_buffer;
for (int i = 0; i < nh; ++i) {
buf[i] = srcbase[i];
}
}
writer += n;
while (writer >= m_size) writer -= m_size;
m_writer = writer;
return n;
}
int zero(int n) {
int available = getWriteSpace();
if (n > available) {
n = available;
}
if (n == 0) return n;
int writer = m_writer;
int here = m_size - writer;
float *const bufbase = m_buffer + writer;
if (here >= n) {
for (int i = 0; i < n; ++i) {
bufbase[i] = 0.f;
}
} else {
for (int i = 0; i < here; ++i) {
bufbase[i] = 0.f;
}
const int nh = n - here;
for (int i = 0; i < nh; ++i) {
m_buffer[i] = 0.f;
}
}
writer += n;
while (writer >= m_size) writer -= m_size;
m_writer = writer;
return n;
}
protected:
float *m_buffer;
int m_writer;
int m_reader;
int m_size;
private:
RingBuffer(const RingBuffer &); // not provided
RingBuffer &operator=(const RingBuffer &); // not provided
};
Plugin *m_plugin;
size_t m_inputStepSize; // value passed to wrapper initialise()
size_t m_inputBlockSize; // value passed to wrapper initialise()
size_t m_setStepSize; // value passed to setPluginStepSize()
size_t m_setBlockSize; // value passed to setPluginBlockSize()
size_t m_stepSize; // value actually used to initialise plugin
size_t m_blockSize; // value actually used to initialise plugin
size_t m_channels;
vector<RingBuffer *> m_queue;
float **m_buffers;
float m_inputSampleRate;
long m_frame;
bool m_unrun;
mutable OutputList m_outputs;
mutable std::map<int, bool> m_rewriteOutputTimes;
void processBlock(FeatureSet& allFeatureSets);
};
PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
PluginWrapper(plugin)
{
m_impl = new Impl(plugin, m_inputSampleRate);
}
PluginBufferingAdapter::~PluginBufferingAdapter()
{
delete m_impl;
}
size_t
PluginBufferingAdapter::getPreferredStepSize() const
{
return getPreferredBlockSize();
}
size_t
PluginBufferingAdapter::getPreferredBlockSize() const
{
return PluginWrapper::getPreferredBlockSize();
}
size_t
PluginBufferingAdapter::getPluginPreferredStepSize() const
{
return PluginWrapper::getPreferredStepSize();
}
size_t
PluginBufferingAdapter::getPluginPreferredBlockSize() const
{
return PluginWrapper::getPreferredBlockSize();
}
void
PluginBufferingAdapter::setPluginStepSize(size_t stepSize)
{
m_impl->setPluginStepSize(stepSize);
}
void
PluginBufferingAdapter::setPluginBlockSize(size_t blockSize)
{
m_impl->setPluginBlockSize(blockSize);
}
void
PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize,
size_t &blockSize)
{
m_impl->getActualStepAndBlockSizes(stepSize, blockSize);
}
bool
PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
return m_impl->initialise(channels, stepSize, blockSize);
}
PluginBufferingAdapter::OutputList
PluginBufferingAdapter::getOutputDescriptors() const
{
return m_impl->getOutputDescriptors();
}
void
PluginBufferingAdapter::setParameter(std::string name, float value)
{
m_impl->setParameter(name, value);
}
void
PluginBufferingAdapter::selectProgram(std::string name)
{
m_impl->selectProgram(name);
}
void
PluginBufferingAdapter::reset()
{
m_impl->reset();
}
PluginBufferingAdapter::FeatureSet
PluginBufferingAdapter::process(const float *const *inputBuffers,
RealTime timestamp)
{
return m_impl->process(inputBuffers, timestamp);
}
PluginBufferingAdapter::FeatureSet
PluginBufferingAdapter::getRemainingFeatures()
{
return m_impl->getRemainingFeatures();
}
PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
m_plugin(plugin),
m_inputStepSize(0),
m_inputBlockSize(0),
m_setStepSize(0),
m_setBlockSize(0),
m_stepSize(0),
m_blockSize(0),
m_channels(0),
m_queue(0),
m_buffers(0),
m_inputSampleRate(inputSampleRate),
m_frame(0),
m_unrun(true)
{
(void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes
}
PluginBufferingAdapter::Impl::~Impl()
{
// the adapter will delete the plugin
for (size_t i = 0; i < m_channels; ++i) {
delete m_queue[i];
delete[] m_buffers[i];
}
delete[] m_buffers;
}
void
PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize)
{
if (m_inputStepSize != 0) {
std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl;
return;
}
m_setStepSize = stepSize;
}
void
PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize)
{
if (m_inputBlockSize != 0) {
std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl;
return;
}
m_setBlockSize = blockSize;
}
void
PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize,
size_t &blockSize)
{
stepSize = m_stepSize;
blockSize = m_blockSize;
}
bool
PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
if (stepSize != blockSize) {
std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
return false;
}
m_channels = channels;
m_inputStepSize = stepSize;
m_inputBlockSize = blockSize;
// if the user has requested particular step or block sizes, use
// those; otherwise use the step and block sizes which the plugin
// prefers
m_stepSize = 0;
m_blockSize = 0;
if (m_setStepSize > 0) {
m_stepSize = m_setStepSize;
}
if (m_setBlockSize > 0) {
m_blockSize = m_setBlockSize;
}
if (m_stepSize == 0 && m_blockSize == 0) {
m_stepSize = m_plugin->getPreferredStepSize();
m_blockSize = m_plugin->getPreferredBlockSize();
}
bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain);
// or sensible defaults if it has no preference
if (m_blockSize == 0) {
if (m_stepSize == 0) {
m_blockSize = 1024;
if (freq) {
m_stepSize = m_blockSize / 2;
} else {
m_stepSize = m_blockSize;
}
} else if (freq) {
m_blockSize = m_stepSize * 2;
} else {
m_blockSize = m_stepSize;
}
} else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above)
if (freq) {
m_stepSize = m_blockSize/2;
} else {
m_stepSize = m_blockSize;
}
}
// current implementation breaks if step is greater than block
if (m_stepSize > m_blockSize) {
size_t newBlockSize;
if (freq) {
newBlockSize = m_stepSize * 2;
} else {
newBlockSize = m_stepSize;
}
std::cerr << "PluginBufferingAdapter::initialise: WARNING: step size " << m_stepSize << " is greater than block size " << m_blockSize << ": cannot handle this in adapter; adjusting block size to " << newBlockSize << std::endl;
m_blockSize = newBlockSize;
}
// std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize
// << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;
m_buffers = new float *[m_channels];
for (size_t i = 0; i < m_channels; ++i) {
m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize));
m_buffers[i] = new float[m_blockSize];
}
bool success = m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
// std::cerr << "PluginBufferingAdapter::initialise: success = " << success << std::endl;
if (success) {
// Re-query outputs; properties such as bin count may have
// changed on initialise
m_outputs.clear();
(void)getOutputDescriptors();
}
return success;
}
PluginBufferingAdapter::OutputList
PluginBufferingAdapter::Impl::getOutputDescriptors() const
{
if (m_outputs.empty()) {
// std::cerr << "PluginBufferingAdapter::getOutputDescriptors: querying anew" << std::endl;
m_outputs = m_plugin->getOutputDescriptors();
}
PluginBufferingAdapter::OutputList outs = m_outputs;
for (size_t i = 0; i < outs.size(); ++i) {
switch (outs[i].sampleType) {
case OutputDescriptor::OneSamplePerStep:
outs[i].sampleType = OutputDescriptor::FixedSampleRate;
outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
m_rewriteOutputTimes[i] = true;
break;
case OutputDescriptor::FixedSampleRate:
if (outs[i].sampleRate == 0.f) {
outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
}
// We actually only need to rewrite output times for
// features that don't have timestamps already, but we
// can't tell from here whether our features will have
// timestamps or not
m_rewriteOutputTimes[i] = true;
break;
case OutputDescriptor::VariableSampleRate:
m_rewriteOutputTimes[i] = false;
break;
}
}
return outs;
}
void
PluginBufferingAdapter::Impl::setParameter(std::string name, float value)
{
m_plugin->setParameter(name, value);
// Re-query outputs; properties such as bin count may have changed
m_outputs.clear();
(void)getOutputDescriptors();
}
void
PluginBufferingAdapter::Impl::selectProgram(std::string name)
{
m_plugin->selectProgram(name);
// Re-query outputs; properties such as bin count may have changed
m_outputs.clear();
(void)getOutputDescriptors();
}
void
PluginBufferingAdapter::Impl::reset()
{
m_frame = 0;
m_unrun = true;
for (size_t i = 0; i < m_queue.size(); ++i) {
m_queue[i]->reset();
}
m_plugin->reset();
}
PluginBufferingAdapter::FeatureSet
PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
RealTime timestamp)
{
if (m_inputStepSize == 0) {
std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl;
return FeatureSet();
}
FeatureSet allFeatureSets;
if (m_unrun) {
m_frame = RealTime::realTime2Frame(timestamp,
int(m_inputSampleRate + 0.5));
m_unrun = false;
}
// queue the new input
for (size_t i = 0; i < m_channels; ++i) {
int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize);
if (written < int(m_inputBlockSize) && i == 0) {
std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: "
<< "Buffer overflow: wrote " << written
<< " of " << m_inputBlockSize
<< " input samples (for plugin step size "
<< m_stepSize << ", block size " << m_blockSize << ")"
<< std::endl;
}
}
// process as much as we can
while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
processBlock(allFeatureSets);
}
return allFeatureSets;
}
PluginBufferingAdapter::FeatureSet
PluginBufferingAdapter::Impl::getRemainingFeatures()
{
FeatureSet allFeatureSets;
// process remaining samples in queue
while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
processBlock(allFeatureSets);
}
// pad any last samples remaining and process
if (m_queue[0]->getReadSpace() > 0) {
for (size_t i = 0; i < m_channels; ++i) {
m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
}
processBlock(allFeatureSets);
}
// get remaining features
FeatureSet featureSet = m_plugin->getRemainingFeatures();
for (map<int, FeatureList>::iterator iter = featureSet.begin();
iter != featureSet.end(); ++iter) {
FeatureList featureList = iter->second;
for (size_t i = 0; i < featureList.size(); ++i) {
allFeatureSets[iter->first].push_back(featureList[i]);
}
}
return allFeatureSets;
}
void
PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
{
for (size_t i = 0; i < m_channels; ++i) {
m_queue[i]->peek(m_buffers[i], m_blockSize);
}
long frame = m_frame;
RealTime timestamp = RealTime::frame2RealTime
(frame, int(m_inputSampleRate + 0.5));
FeatureSet featureSet = m_plugin->process(m_buffers, timestamp);
PluginWrapper *wrapper = dynamic_cast<PluginWrapper *>(m_plugin);
RealTime adjustment;
if (wrapper) {
PluginInputDomainAdapter *ida =
wrapper->getWrapper<PluginInputDomainAdapter>();
if (ida) adjustment = ida->getTimestampAdjustment();
}
for (FeatureSet::iterator iter = featureSet.begin();
iter != featureSet.end(); ++iter) {
int outputNo = iter->first;
if (m_rewriteOutputTimes[outputNo]) {
FeatureList featureList = iter->second;
for (size_t i = 0; i < featureList.size(); ++i) {
switch (m_outputs[outputNo].sampleType) {
case OutputDescriptor::OneSamplePerStep:
// use our internal timestamp, always
featureList[i].timestamp = timestamp + adjustment;
featureList[i].hasTimestamp = true;
break;
case OutputDescriptor::FixedSampleRate:
// use our internal timestamp if feature lacks one
if (!featureList[i].hasTimestamp) {
featureList[i].timestamp = timestamp + adjustment;
featureList[i].hasTimestamp = true;
}
break;
case OutputDescriptor::VariableSampleRate:
break; // plugin must set timestamp
default:
break;
}
allFeatureSets[outputNo].push_back(featureList[i]);
}
} else {
for (size_t i = 0; i < iter->second.size(); ++i) {
allFeatureSets[outputNo].push_back(iter->second[i]);
}
}
}
// step forward
for (size_t i = 0; i < m_channels; ++i) {
m_queue[i]->skip(m_stepSize);
}
// increment internal frame counter each time we step forward
m_frame += m_stepSize;
}
}
}
_VAMP_SDK_HOSTSPACE_END(PluginBufferingAdapter.cpp)

View File

@@ -1,270 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include "vamp-hostsdk/PluginChannelAdapter.h"
_VAMP_SDK_HOSTSPACE_BEGIN(PluginChannelAdapter.cpp)
namespace Vamp {
namespace HostExt {
class PluginChannelAdapter::Impl
{
public:
Impl(Plugin *plugin);
~Impl();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet processInterleaved(const float *inputBuffers, RealTime timestamp);
protected:
Plugin *m_plugin;
size_t m_blockSize;
size_t m_inputChannels;
size_t m_pluginChannels;
float **m_buffer;
float **m_deinterleave;
const float **m_forwardPtrs;
};
PluginChannelAdapter::PluginChannelAdapter(Plugin *plugin) :
PluginWrapper(plugin)
{
m_impl = new Impl(plugin);
}
PluginChannelAdapter::~PluginChannelAdapter()
{
delete m_impl;
}
bool
PluginChannelAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
return m_impl->initialise(channels, stepSize, blockSize);
}
PluginChannelAdapter::FeatureSet
PluginChannelAdapter::process(const float *const *inputBuffers,
RealTime timestamp)
{
return m_impl->process(inputBuffers, timestamp);
}
PluginChannelAdapter::FeatureSet
PluginChannelAdapter::processInterleaved(const float *inputBuffers,
RealTime timestamp)
{
return m_impl->processInterleaved(inputBuffers, timestamp);
}
PluginChannelAdapter::Impl::Impl(Plugin *plugin) :
m_plugin(plugin),
m_blockSize(0),
m_inputChannels(0),
m_pluginChannels(0),
m_buffer(0),
m_deinterleave(0),
m_forwardPtrs(0)
{
}
PluginChannelAdapter::Impl::~Impl()
{
// the adapter will delete the plugin
if (m_buffer) {
if (m_inputChannels > m_pluginChannels) {
delete[] m_buffer[0];
} else {
for (size_t i = 0; i < m_pluginChannels - m_inputChannels; ++i) {
delete[] m_buffer[i];
}
}
delete[] m_buffer;
m_buffer = 0;
}
if (m_deinterleave) {
for (size_t i = 0; i < m_inputChannels; ++i) {
delete[] m_deinterleave[i];
}
delete[] m_deinterleave;
m_deinterleave = 0;
}
if (m_forwardPtrs) {
delete[] m_forwardPtrs;
m_forwardPtrs = 0;
}
}
bool
PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
m_blockSize = blockSize;
size_t minch = m_plugin->getMinChannelCount();
size_t maxch = m_plugin->getMaxChannelCount();
m_inputChannels = channels;
if (m_inputChannels < minch) {
m_forwardPtrs = new const float *[minch];
if (m_inputChannels > 1) {
// We need a set of zero-valued buffers to add to the
// forwarded pointers
m_buffer = new float*[minch - channels];
for (size_t i = 0; i < minch; ++i) {
m_buffer[i] = new float[blockSize];
for (size_t j = 0; j < blockSize; ++j) {
m_buffer[i][j] = 0.f;
}
}
}
m_pluginChannels = minch;
// std::cerr << "PluginChannelAdapter::initialise: expanding " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
} else if (m_inputChannels > maxch) {
// We only need m_buffer if we are mixing down to a single
// channel -- otherwise we can just forward the same float* as
// passed in to process(), expecting the excess to be ignored
if (maxch == 1) {
m_buffer = new float *[1];
m_buffer[0] = new float[blockSize];
// std::cerr << "PluginChannelAdapter::initialise: mixing " << m_inputChannels << " to mono for plugin" << std::endl;
} else {
// std::cerr << "PluginChannelAdapter::initialise: reducing " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
}
m_pluginChannels = maxch;
} else {
// std::cerr << "PluginChannelAdapter::initialise: accepting given number of channels (" << m_inputChannels << ")" << std::endl;
m_pluginChannels = m_inputChannels;
}
return m_plugin->initialise(m_pluginChannels, stepSize, blockSize);
}
PluginChannelAdapter::FeatureSet
PluginChannelAdapter::Impl::processInterleaved(const float *inputBuffers,
RealTime timestamp)
{
if (!m_deinterleave) {
m_deinterleave = new float *[m_inputChannels];
for (size_t i = 0; i < m_inputChannels; ++i) {
m_deinterleave[i] = new float[m_blockSize];
}
}
for (size_t i = 0; i < m_inputChannels; ++i) {
for (size_t j = 0; j < m_blockSize; ++j) {
m_deinterleave[i][j] = inputBuffers[j * m_inputChannels + i];
}
}
return process(m_deinterleave, timestamp);
}
PluginChannelAdapter::FeatureSet
PluginChannelAdapter::Impl::process(const float *const *inputBuffers,
RealTime timestamp)
{
// std::cerr << "PluginChannelAdapter::process: " << m_inputChannels << " -> " << m_pluginChannels << " channels" << std::endl;
if (m_inputChannels < m_pluginChannels) {
if (m_inputChannels == 1) {
for (size_t i = 0; i < m_pluginChannels; ++i) {
m_forwardPtrs[i] = inputBuffers[0];
}
} else {
for (size_t i = 0; i < m_inputChannels; ++i) {
m_forwardPtrs[i] = inputBuffers[i];
}
for (size_t i = m_inputChannels; i < m_pluginChannels; ++i) {
m_forwardPtrs[i] = m_buffer[i - m_inputChannels];
}
}
return m_plugin->process(m_forwardPtrs, timestamp);
} else if (m_inputChannels > m_pluginChannels) {
if (m_pluginChannels == 1) {
for (size_t j = 0; j < m_blockSize; ++j) {
m_buffer[0][j] = inputBuffers[0][j];
}
for (size_t i = 1; i < m_inputChannels; ++i) {
for (size_t j = 0; j < m_blockSize; ++j) {
m_buffer[0][j] += inputBuffers[i][j];
}
}
for (size_t j = 0; j < m_blockSize; ++j) {
m_buffer[0][j] /= m_inputChannels;
}
return m_plugin->process(m_buffer, timestamp);
} else {
return m_plugin->process(inputBuffers, timestamp);
}
} else {
return m_plugin->process(inputBuffers, timestamp);
}
}
}
}
_VAMP_SDK_HOSTSPACE_END(PluginChannelAdapter.cpp)

View File

@@ -1,456 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include "vamp-hostsdk/PluginHostAdapter.h"
#include <cstdlib>
#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 2 )
#error Unexpected version of Vamp SDK header included
#endif
_VAMP_SDK_HOSTSPACE_BEGIN(PluginHostAdapter.cpp)
namespace Vamp
{
PluginHostAdapter::PluginHostAdapter(const VampPluginDescriptor *descriptor,
float inputSampleRate) :
Plugin(inputSampleRate),
m_descriptor(descriptor)
{
// std::cerr << "PluginHostAdapter::PluginHostAdapter (plugin = " << descriptor->name << ")" << std::endl;
m_handle = m_descriptor->instantiate(m_descriptor, inputSampleRate);
if (!m_handle) {
// std::cerr << "WARNING: PluginHostAdapter: Plugin instantiation failed for plugin " << m_descriptor->name << std::endl;
}
}
PluginHostAdapter::~PluginHostAdapter()
{
// std::cerr << "PluginHostAdapter::~PluginHostAdapter (plugin = " << m_descriptor->name << ")" << std::endl;
if (m_handle) m_descriptor->cleanup(m_handle);
}
std::vector<std::string>
PluginHostAdapter::getPluginPath()
{
std::vector<std::string> path;
std::string envPath;
char *cpath = getenv("VAMP_PATH");
if (cpath) envPath = cpath;
#ifdef _WIN32
#define PATH_SEPARATOR ';'
#define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins"
#else
#define PATH_SEPARATOR ':'
#ifdef __APPLE__
#define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp"
#else
#define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp"
#endif
#endif
if (envPath == "") {
envPath = DEFAULT_VAMP_PATH;
char *chome = getenv("HOME");
if (chome) {
std::string home(chome);
std::string::size_type f;
while ((f = envPath.find("$HOME")) != std::string::npos &&
f < envPath.length()) {
envPath.replace(f, 5, home);
}
}
#ifdef _WIN32
char *cpfiles = getenv("ProgramFiles");
if (!cpfiles) cpfiles = (char *)"C:\\Program Files";
std::string pfiles(cpfiles);
std::string::size_type f;
while ((f = envPath.find("%ProgramFiles%")) != std::string::npos &&
f < envPath.length()) {
envPath.replace(f, 14, pfiles);
}
#endif
}
std::string::size_type index = 0, newindex = 0;
while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) {
path.push_back(envPath.substr(index, newindex - index));
index = newindex + 1;
}
path.push_back(envPath.substr(index));
return path;
}
bool
PluginHostAdapter::initialise(size_t channels,
size_t stepSize,
size_t blockSize)
{
if (!m_handle) return false;
return m_descriptor->initialise(m_handle, channels, stepSize, blockSize) ?
true : false;
}
void
PluginHostAdapter::reset()
{
if (!m_handle) {
// std::cerr << "PluginHostAdapter::reset: no handle" << std::endl;
return;
}
// std::cerr << "PluginHostAdapter::reset(" << m_handle << ")" << std::endl;
m_descriptor->reset(m_handle);
}
PluginHostAdapter::InputDomain
PluginHostAdapter::getInputDomain() const
{
if (m_descriptor->inputDomain == vampFrequencyDomain) {
return FrequencyDomain;
} else {
return TimeDomain;
}
}
unsigned int
PluginHostAdapter::getVampApiVersion() const
{
return m_descriptor->vampApiVersion;
}
std::string
PluginHostAdapter::getIdentifier() const
{
return m_descriptor->identifier;
}
std::string
PluginHostAdapter::getName() const
{
return m_descriptor->name;
}
std::string
PluginHostAdapter::getDescription() const
{
return m_descriptor->description;
}
std::string
PluginHostAdapter::getMaker() const
{
return m_descriptor->maker;
}
int
PluginHostAdapter::getPluginVersion() const
{
return m_descriptor->pluginVersion;
}
std::string
PluginHostAdapter::getCopyright() const
{
return m_descriptor->copyright;
}
PluginHostAdapter::ParameterList
PluginHostAdapter::getParameterDescriptors() const
{
ParameterList list;
for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
const VampParameterDescriptor *spd = m_descriptor->parameters[i];
ParameterDescriptor pd;
pd.identifier = spd->identifier;
pd.name = spd->name;
pd.description = spd->description;
pd.unit = spd->unit;
pd.minValue = spd->minValue;
pd.maxValue = spd->maxValue;
pd.defaultValue = spd->defaultValue;
pd.isQuantized = spd->isQuantized;
pd.quantizeStep = spd->quantizeStep;
if (pd.isQuantized && spd->valueNames) {
for (unsigned int j = 0; spd->valueNames[j]; ++j) {
pd.valueNames.push_back(spd->valueNames[j]);
}
}
list.push_back(pd);
}
return list;
}
float
PluginHostAdapter::getParameter(std::string param) const
{
if (!m_handle) return 0.0;
for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
if (param == m_descriptor->parameters[i]->identifier) {
return m_descriptor->getParameter(m_handle, i);
}
}
return 0.0;
}
void
PluginHostAdapter::setParameter(std::string param,
float value)
{
if (!m_handle) return;
for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) {
if (param == m_descriptor->parameters[i]->identifier) {
m_descriptor->setParameter(m_handle, i, value);
return;
}
}
}
PluginHostAdapter::ProgramList
PluginHostAdapter::getPrograms() const
{
ProgramList list;
for (unsigned int i = 0; i < m_descriptor->programCount; ++i) {
list.push_back(m_descriptor->programs[i]);
}
return list;
}
std::string
PluginHostAdapter::getCurrentProgram() const
{
if (!m_handle) return "";
int pn = m_descriptor->getCurrentProgram(m_handle);
return m_descriptor->programs[pn];
}
void
PluginHostAdapter::selectProgram(std::string program)
{
if (!m_handle) return;
for (unsigned int i = 0; i < m_descriptor->programCount; ++i) {
if (program == m_descriptor->programs[i]) {
m_descriptor->selectProgram(m_handle, i);
return;
}
}
}
size_t
PluginHostAdapter::getPreferredStepSize() const
{
if (!m_handle) return 0;
return m_descriptor->getPreferredStepSize(m_handle);
}
size_t
PluginHostAdapter::getPreferredBlockSize() const
{
if (!m_handle) return 0;
return m_descriptor->getPreferredBlockSize(m_handle);
}
size_t
PluginHostAdapter::getMinChannelCount() const
{
if (!m_handle) return 0;
return m_descriptor->getMinChannelCount(m_handle);
}
size_t
PluginHostAdapter::getMaxChannelCount() const
{
if (!m_handle) return 0;
return m_descriptor->getMaxChannelCount(m_handle);
}
PluginHostAdapter::OutputList
PluginHostAdapter::getOutputDescriptors() const
{
OutputList list;
if (!m_handle) {
// std::cerr << "PluginHostAdapter::getOutputDescriptors: no handle " << std::endl;
return list;
}
unsigned int count = m_descriptor->getOutputCount(m_handle);
for (unsigned int i = 0; i < count; ++i) {
VampOutputDescriptor *sd = m_descriptor->getOutputDescriptor(m_handle, i);
OutputDescriptor d;
d.identifier = sd->identifier;
d.name = sd->name;
d.description = sd->description;
d.unit = sd->unit;
d.hasFixedBinCount = sd->hasFixedBinCount;
d.binCount = sd->binCount;
if (d.hasFixedBinCount && sd->binNames) {
for (unsigned int j = 0; j < sd->binCount; ++j) {
d.binNames.push_back(sd->binNames[j] ? sd->binNames[j] : "");
}
}
d.hasKnownExtents = sd->hasKnownExtents;
d.minValue = sd->minValue;
d.maxValue = sd->maxValue;
d.isQuantized = sd->isQuantized;
d.quantizeStep = sd->quantizeStep;
switch (sd->sampleType) {
case vampOneSamplePerStep:
d.sampleType = OutputDescriptor::OneSamplePerStep; break;
case vampFixedSampleRate:
d.sampleType = OutputDescriptor::FixedSampleRate; break;
case vampVariableSampleRate:
d.sampleType = OutputDescriptor::VariableSampleRate; break;
}
d.sampleRate = sd->sampleRate;
if (m_descriptor->vampApiVersion >= 2) {
d.hasDuration = sd->hasDuration;
} else {
d.hasDuration = false;
}
list.push_back(d);
m_descriptor->releaseOutputDescriptor(sd);
}
return list;
}
PluginHostAdapter::FeatureSet
PluginHostAdapter::process(const float *const *inputBuffers,
RealTime timestamp)
{
FeatureSet fs;
if (!m_handle) return fs;
int sec = timestamp.sec;
int nsec = timestamp.nsec;
VampFeatureList *features = m_descriptor->process(m_handle,
inputBuffers,
sec, nsec);
convertFeatures(features, fs);
m_descriptor->releaseFeatureSet(features);
return fs;
}
PluginHostAdapter::FeatureSet
PluginHostAdapter::getRemainingFeatures()
{
FeatureSet fs;
if (!m_handle) return fs;
VampFeatureList *features = m_descriptor->getRemainingFeatures(m_handle);
convertFeatures(features, fs);
m_descriptor->releaseFeatureSet(features);
return fs;
}
void
PluginHostAdapter::convertFeatures(VampFeatureList *features,
FeatureSet &fs)
{
if (!features) return;
unsigned int outputs = m_descriptor->getOutputCount(m_handle);
for (unsigned int i = 0; i < outputs; ++i) {
VampFeatureList &list = features[i];
if (list.featureCount > 0) {
Feature feature;
feature.values.reserve(list.features[0].v1.valueCount);
for (unsigned int j = 0; j < list.featureCount; ++j) {
feature.hasTimestamp = list.features[j].v1.hasTimestamp;
feature.timestamp = RealTime(list.features[j].v1.sec,
list.features[j].v1.nsec);
feature.hasDuration = false;
if (m_descriptor->vampApiVersion >= 2) {
unsigned int j2 = j + list.featureCount;
feature.hasDuration = list.features[j2].v2.hasDuration;
feature.duration = RealTime(list.features[j2].v2.durationSec,
list.features[j2].v2.durationNsec);
}
for (unsigned int k = 0; k < list.features[j].v1.valueCount; ++k) {
feature.values.push_back(list.features[j].v1.values[k]);
}
if (list.features[j].v1.label) {
feature.label = list.features[j].v1.label;
}
fs[i].push_back(feature);
if (list.features[j].v1.valueCount > 0) {
feature.values.clear();
}
if (list.features[j].v1.label) {
feature.label = "";
}
}
}
}
}
}
_VAMP_SDK_HOSTSPACE_END(PluginHostAdapter.cpp)

View File

@@ -1,673 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2009 Chris Cannam and QMUL.
This file is based in part on Don Cross's public domain FFT
implementation.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include "vamp-hostsdk/PluginInputDomainAdapter.h"
#include <cmath>
/**
* If you want to compile using FFTW instead of the built-in FFT
* implementation for the PluginInputDomainAdapter, define HAVE_FFTW3
* in the Makefile.
*
* Be aware that FFTW is licensed under the GPL -- unlike this SDK,
* which is provided under a more liberal BSD license in order to
* permit use in closed source applications. The use of FFTW would
* mean that your code would need to be licensed under the GPL as
* well. Do not define this symbol unless you understand and accept
* the implications of this.
*
* Parties such as Linux distribution packagers who redistribute this
* SDK for use in other programs should _not_ define this symbol, as
* it would change the effective licensing terms under which the SDK
* was available to third party developers.
*
* The default is not to use FFTW, and to use the built-in FFT instead.
*
* Note: The FFTW code uses FFTW_MEASURE, and so will perform badly on
* its first invocation unless the host has saved and restored FFTW
* wisdom (see the FFTW documentation).
*/
#ifdef HAVE_FFTW3
#include <fftw3.h>
#endif
_VAMP_SDK_HOSTSPACE_BEGIN(PluginInputDomainAdapter.cpp)
namespace Vamp {
namespace HostExt {
class PluginInputDomainAdapter::Impl
{
public:
Impl(Plugin *plugin, float inputSampleRate);
~Impl();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
size_t getPreferredStepSize() const;
size_t getPreferredBlockSize() const;
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
void setProcessTimestampMethod(ProcessTimestampMethod m);
ProcessTimestampMethod getProcessTimestampMethod() const;
RealTime getTimestampAdjustment() const;
protected:
Plugin *m_plugin;
float m_inputSampleRate;
int m_channels;
int m_stepSize;
int m_blockSize;
float **m_freqbuf;
double *m_ri;
double *m_window;
ProcessTimestampMethod m_method;
int m_processCount;
float **m_shiftBuffers;
#ifdef HAVE_FFTW3
fftw_plan m_plan;
fftw_complex *m_cbuf;
#else
double *m_ro;
double *m_io;
void fft(unsigned int n, bool inverse,
double *ri, double *ii, double *ro, double *io);
#endif
FeatureSet processShiftingTimestamp(const float *const *inputBuffers, RealTime timestamp);
FeatureSet processShiftingData(const float *const *inputBuffers, RealTime timestamp);
size_t makeBlockSizeAcceptable(size_t) const;
};
PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
PluginWrapper(plugin)
{
m_impl = new Impl(plugin, m_inputSampleRate);
}
PluginInputDomainAdapter::~PluginInputDomainAdapter()
{
delete m_impl;
}
bool
PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
return m_impl->initialise(channels, stepSize, blockSize);
}
void
PluginInputDomainAdapter::reset()
{
m_impl->reset();
}
Plugin::InputDomain
PluginInputDomainAdapter::getInputDomain() const
{
return TimeDomain;
}
size_t
PluginInputDomainAdapter::getPreferredStepSize() const
{
return m_impl->getPreferredStepSize();
}
size_t
PluginInputDomainAdapter::getPreferredBlockSize() const
{
return m_impl->getPreferredBlockSize();
}
Plugin::FeatureSet
PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp)
{
return m_impl->process(inputBuffers, timestamp);
}
void
PluginInputDomainAdapter::setProcessTimestampMethod(ProcessTimestampMethod m)
{
m_impl->setProcessTimestampMethod(m);
}
PluginInputDomainAdapter::ProcessTimestampMethod
PluginInputDomainAdapter::getProcessTimestampMethod() const
{
return m_impl->getProcessTimestampMethod();
}
RealTime
PluginInputDomainAdapter::getTimestampAdjustment() const
{
return m_impl->getTimestampAdjustment();
}
PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
m_plugin(plugin),
m_inputSampleRate(inputSampleRate),
m_channels(0),
m_stepSize(0),
m_blockSize(0),
m_freqbuf(0),
m_ri(0),
m_window(0),
m_method(ShiftTimestamp),
m_processCount(0),
m_shiftBuffers(0),
#ifdef HAVE_FFTW3
m_plan(0),
m_cbuf(0)
#else
m_ro(0),
m_io(0)
#endif
{
}
PluginInputDomainAdapter::Impl::~Impl()
{
// the adapter will delete the plugin
if (m_shiftBuffers) {
for (int c = 0; c < m_channels; ++c) {
delete[] m_shiftBuffers[c];
}
delete[] m_shiftBuffers;
}
if (m_channels > 0) {
for (int c = 0; c < m_channels; ++c) {
delete[] m_freqbuf[c];
}
delete[] m_freqbuf;
#ifdef HAVE_FFTW3
if (m_plan) {
fftw_destroy_plan(m_plan);
fftw_free(m_ri);
fftw_free(m_cbuf);
m_plan = 0;
}
#else
delete[] m_ri;
delete[] m_ro;
delete[] m_io;
#endif
delete[] m_window;
}
}
// for some visual studii apparently
#ifndef M_PI
#define M_PI 3.14159265358979232846
#endif
bool
PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
if (m_plugin->getInputDomain() == TimeDomain) {
m_stepSize = int(stepSize);
m_blockSize = int(blockSize);
m_channels = int(channels);
return m_plugin->initialise(channels, stepSize, blockSize);
}
if (blockSize < 2) {
std::cerr << "ERROR: PluginInputDomainAdapter::initialise: blocksize < 2 not supported" << std::endl;
return false;
}
if (blockSize & (blockSize-1)) {
std::cerr << "ERROR: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl;
return false;
}
if (m_channels > 0) {
for (int c = 0; c < m_channels; ++c) {
delete[] m_freqbuf[c];
}
delete[] m_freqbuf;
#ifdef HAVE_FFTW3
if (m_plan) {
fftw_destroy_plan(m_plan);
fftw_free(m_ri);
fftw_free(m_cbuf);
m_plan = 0;
}
#else
delete[] m_ri;
delete[] m_ro;
delete[] m_io;
#endif
delete[] m_window;
}
m_stepSize = int(stepSize);
m_blockSize = int(blockSize);
m_channels = int(channels);
m_freqbuf = new float *[m_channels];
for (int c = 0; c < m_channels; ++c) {
m_freqbuf[c] = new float[m_blockSize + 2];
}
m_window = new double[m_blockSize];
for (int i = 0; i < m_blockSize; ++i) {
// Hanning window
m_window[i] = (0.50 - 0.50 * cos((2.0 * M_PI * i) / m_blockSize));
}
#ifdef HAVE_FFTW3
m_ri = (double *)fftw_malloc(blockSize * sizeof(double));
m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex));
m_plan = fftw_plan_dft_r2c_1d(blockSize, m_ri, m_cbuf, FFTW_MEASURE);
#else
m_ri = new double[m_blockSize];
m_ro = new double[m_blockSize];
m_io = new double[m_blockSize];
#endif
m_processCount = 0;
return m_plugin->initialise(channels, stepSize, blockSize);
}
void
PluginInputDomainAdapter::Impl::reset()
{
m_processCount = 0;
m_plugin->reset();
}
size_t
PluginInputDomainAdapter::Impl::getPreferredStepSize() const
{
size_t step = m_plugin->getPreferredStepSize();
if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) {
step = getPreferredBlockSize() / 2;
}
return step;
}
size_t
PluginInputDomainAdapter::Impl::getPreferredBlockSize() const
{
size_t block = m_plugin->getPreferredBlockSize();
if (m_plugin->getInputDomain() == FrequencyDomain) {
if (block == 0) {
block = 1024;
} else {
block = makeBlockSizeAcceptable(block);
}
}
return block;
}
size_t
PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
{
if (blockSize < 2) {
std::cerr << "WARNING: PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl
<< "supported, increasing from " << blockSize << " to 2" << std::endl;
blockSize = 2;
} else if (blockSize & (blockSize-1)) {
#ifdef HAVE_FFTW3
// not an issue with FFTW
#else
// not a power of two, can't handle that with our built-in FFT
// implementation
size_t nearest = blockSize;
size_t power = 0;
while (nearest > 1) {
nearest >>= 1;
++power;
}
nearest = 1;
while (power) {
nearest <<= 1;
--power;
}
if (blockSize - nearest > (nearest*2) - blockSize) {
nearest = nearest*2;
}
std::cerr << "WARNING: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
blockSize = nearest;
#endif
}
return blockSize;
}
RealTime
PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
{
if (m_plugin->getInputDomain() == TimeDomain) {
return RealTime::zeroTime;
} else if (m_method == ShiftData || m_method == NoShift) {
return RealTime::zeroTime;
} else {
return RealTime::frame2RealTime
(m_blockSize/2, int(m_inputSampleRate + 0.5));
}
}
void
PluginInputDomainAdapter::Impl::setProcessTimestampMethod(ProcessTimestampMethod m)
{
m_method = m;
}
PluginInputDomainAdapter::ProcessTimestampMethod
PluginInputDomainAdapter::Impl::getProcessTimestampMethod() const
{
return m_method;
}
Plugin::FeatureSet
PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
RealTime timestamp)
{
if (m_plugin->getInputDomain() == TimeDomain) {
return m_plugin->process(inputBuffers, timestamp);
}
if (m_method == ShiftTimestamp || m_method == NoShift) {
return processShiftingTimestamp(inputBuffers, timestamp);
} else {
return processShiftingData(inputBuffers, timestamp);
}
}
Plugin::FeatureSet
PluginInputDomainAdapter::Impl::processShiftingTimestamp(const float *const *inputBuffers,
RealTime timestamp)
{
if (m_method == ShiftTimestamp) {
timestamp = timestamp + getTimestampAdjustment();
}
for (int c = 0; c < m_channels; ++c) {
for (int i = 0; i < m_blockSize; ++i) {
m_ri[i] = double(inputBuffers[c][i]) * m_window[i];
}
for (int i = 0; i < m_blockSize/2; ++i) {
// FFT shift
double value = m_ri[i];
m_ri[i] = m_ri[i + m_blockSize/2];
m_ri[i + m_blockSize/2] = value;
}
#ifdef HAVE_FFTW3
fftw_execute(m_plan);
for (int i = 0; i <= m_blockSize/2; ++i) {
m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
}
#else
fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
for (int i = 0; i <= m_blockSize/2; ++i) {
m_freqbuf[c][i * 2] = float(m_ro[i]);
m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
}
#endif
}
return m_plugin->process(m_freqbuf, timestamp);
}
Plugin::FeatureSet
PluginInputDomainAdapter::Impl::processShiftingData(const float *const *inputBuffers,
RealTime timestamp)
{
if (m_processCount == 0) {
if (!m_shiftBuffers) {
m_shiftBuffers = new float *[m_channels];
for (int c = 0; c < m_channels; ++c) {
m_shiftBuffers[c] = new float[m_blockSize + m_blockSize/2];
}
}
for (int c = 0; c < m_channels; ++c) {
for (int i = 0; i < m_blockSize + m_blockSize/2; ++i) {
m_shiftBuffers[c][i] = 0.f;
}
}
}
for (int c = 0; c < m_channels; ++c) {
for (int i = m_stepSize; i < m_blockSize + m_blockSize/2; ++i) {
m_shiftBuffers[c][i - m_stepSize] = m_shiftBuffers[c][i];
}
for (int i = 0; i < m_blockSize; ++i) {
m_shiftBuffers[c][i + m_blockSize/2] = inputBuffers[c][i];
}
}
for (int c = 0; c < m_channels; ++c) {
for (int i = 0; i < m_blockSize; ++i) {
m_ri[i] = double(m_shiftBuffers[c][i]) * m_window[i];
}
for (int i = 0; i < m_blockSize/2; ++i) {
// FFT shift
double value = m_ri[i];
m_ri[i] = m_ri[i + m_blockSize/2];
m_ri[i + m_blockSize/2] = value;
}
#ifdef HAVE_FFTW3
fftw_execute(m_plan);
for (int i = 0; i <= m_blockSize/2; ++i) {
m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
}
#else
fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
for (int i = 0; i <= m_blockSize/2; ++i) {
m_freqbuf[c][i * 2] = float(m_ro[i]);
m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
}
#endif
}
++m_processCount;
return m_plugin->process(m_freqbuf, timestamp);
}
#ifndef HAVE_FFTW3
void
PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse,
double *ri, double *ii, double *ro, double *io)
{
if (!ri || !ro || !io) return;
unsigned int bits;
unsigned int i, j, k, m;
unsigned int blockSize, blockEnd;
double tr, ti;
if (n < 2) return;
if (n & (n-1)) return;
double angle = 2.0 * M_PI;
if (inverse) angle = -angle;
for (i = 0; ; ++i) {
if (n & (1 << i)) {
bits = i;
break;
}
}
static unsigned int tableSize = 0;
static int *table = 0;
if (tableSize != n) {
delete[] table;
table = new int[n];
for (i = 0; i < n; ++i) {
m = i;
for (j = k = 0; j < bits; ++j) {
k = (k << 1) | (m & 1);
m >>= 1;
}
table[i] = k;
}
tableSize = n;
}
if (ii) {
for (i = 0; i < n; ++i) {
ro[table[i]] = ri[i];
io[table[i]] = ii[i];
}
} else {
for (i = 0; i < n; ++i) {
ro[table[i]] = ri[i];
io[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;
}
if (inverse) {
double denom = (double)n;
for (i = 0; i < n; i++) {
ro[i] /= denom;
io[i] /= denom;
}
}
}
#endif
}
}
_VAMP_SDK_HOSTSPACE_END(PluginInputDomainAdapter.cpp)

View File

@@ -1,707 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include "vamp-hostsdk/PluginHostAdapter.h"
#include "vamp-hostsdk/PluginLoader.h"
#include "vamp-hostsdk/PluginInputDomainAdapter.h"
#include "vamp-hostsdk/PluginChannelAdapter.h"
#include "vamp-hostsdk/PluginBufferingAdapter.h"
#include <fstream>
#include <cctype> // tolower
#include <cstring>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#define PLUGIN_SUFFIX "dll"
#else /* ! _WIN32 */
#include <dirent.h>
#include <dlfcn.h>
#ifdef __APPLE__
#define PLUGIN_SUFFIX "dylib"
#else /* ! __APPLE__ */
#define PLUGIN_SUFFIX "so"
#endif /* ! __APPLE__ */
#endif /* ! _WIN32 */
using namespace std;
_VAMP_SDK_HOSTSPACE_BEGIN(PluginLoader.cpp)
namespace Vamp {
namespace HostExt {
class PluginLoader::Impl
{
public:
Impl();
virtual ~Impl();
PluginKeyList listPlugins();
Plugin *loadPlugin(PluginKey key,
float inputSampleRate,
int adapterFlags);
PluginKey composePluginKey(string libraryName, string identifier);
PluginCategoryHierarchy getPluginCategory(PluginKey key);
string getLibraryPathForPlugin(PluginKey key);
static void setInstanceToClean(PluginLoader *instance);
protected:
class PluginDeletionNotifyAdapter : public PluginWrapper {
public:
PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader);
virtual ~PluginDeletionNotifyAdapter();
protected:
Impl *m_loader;
};
class InstanceCleaner {
public:
InstanceCleaner() : m_instance(0) { }
~InstanceCleaner() { delete m_instance; }
void setInstance(PluginLoader *instance) { m_instance = instance; }
protected:
PluginLoader *m_instance;
};
virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter);
map<PluginKey, string> m_pluginLibraryNameMap;
bool m_allPluginsEnumerated;
void enumeratePlugins(PluginKey forPlugin = "");
map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
void generateTaxonomy();
map<Plugin *, void *> m_pluginLibraryHandleMap;
bool decomposePluginKey(PluginKey key,
string &libraryName, string &identifier);
void *loadLibrary(string path);
void unloadLibrary(void *handle);
void *lookupInLibrary(void *handle, const char *symbol);
string splicePath(string a, string b);
vector<string> listFiles(string dir, string ext);
static InstanceCleaner m_cleaner;
};
PluginLoader *
PluginLoader::m_instance = 0;
PluginLoader::Impl::InstanceCleaner
PluginLoader::Impl::m_cleaner;
PluginLoader::PluginLoader()
{
m_impl = new Impl();
}
PluginLoader::~PluginLoader()
{
delete m_impl;
}
PluginLoader *
PluginLoader::getInstance()
{
if (!m_instance) {
// The cleaner doesn't own the instance, because we leave the
// instance pointer in the base class for binary backwards
// compatibility reasons and to avoid waste
m_instance = new PluginLoader();
Impl::setInstanceToClean(m_instance);
}
return m_instance;
}
vector<PluginLoader::PluginKey>
PluginLoader::listPlugins()
{
return m_impl->listPlugins();
}
Plugin *
PluginLoader::loadPlugin(PluginKey key,
float inputSampleRate,
int adapterFlags)
{
return m_impl->loadPlugin(key, inputSampleRate, adapterFlags);
}
PluginLoader::PluginKey
PluginLoader::composePluginKey(string libraryName, string identifier)
{
return m_impl->composePluginKey(libraryName, identifier);
}
PluginLoader::PluginCategoryHierarchy
PluginLoader::getPluginCategory(PluginKey key)
{
return m_impl->getPluginCategory(key);
}
string
PluginLoader::getLibraryPathForPlugin(PluginKey key)
{
return m_impl->getLibraryPathForPlugin(key);
}
PluginLoader::Impl::Impl() :
m_allPluginsEnumerated(false)
{
}
PluginLoader::Impl::~Impl()
{
}
void
PluginLoader::Impl::setInstanceToClean(PluginLoader *instance)
{
m_cleaner.setInstance(instance);
}
vector<PluginLoader::PluginKey>
PluginLoader::Impl::listPlugins()
{
if (!m_allPluginsEnumerated) enumeratePlugins();
vector<PluginKey> plugins;
for (map<PluginKey, string>::iterator mi = m_pluginLibraryNameMap.begin();
mi != m_pluginLibraryNameMap.end(); ++mi) {
plugins.push_back(mi->first);
}
return plugins;
}
void
PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin)
{
vector<string> path = PluginHostAdapter::getPluginPath();
string libraryName, identifier;
if (forPlugin != "") {
if (!decomposePluginKey(forPlugin, libraryName, identifier)) {
std::cerr << "WARNING: Vamp::HostExt::PluginLoader: Invalid plugin key \""
<< forPlugin << "\" in enumerate" << std::endl;
return;
}
}
for (size_t i = 0; i < path.size(); ++i) {
vector<string> files = listFiles(path[i], PLUGIN_SUFFIX);
for (vector<string>::iterator fi = files.begin();
fi != files.end(); ++fi) {
if (libraryName != "") {
// libraryName is lowercased and lacking an extension,
// as it came from the plugin key
string temp = *fi;
for (size_t i = 0; i < temp.length(); ++i) {
temp[i] = tolower(temp[i]);
}
string::size_type pi = temp.find('.');
if (pi == string::npos) {
if (libraryName != temp) continue;
} else {
if (libraryName != temp.substr(0, pi)) continue;
}
}
string fullPath = path[i];
fullPath = splicePath(fullPath, *fi);
void *handle = loadLibrary(fullPath);
if (!handle) continue;
VampGetPluginDescriptorFunction fn =
(VampGetPluginDescriptorFunction)lookupInLibrary
(handle, "vampGetPluginDescriptor");
if (!fn) {
if (forPlugin != "") {
cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
<< fullPath << "\"" << endl;
}
unloadLibrary(handle);
continue;
}
int index = 0;
const VampPluginDescriptor *descriptor = 0;
bool found = false;
while ((descriptor = fn(VAMP_API_VERSION, index))) {
++index;
if (identifier != "") {
if (descriptor->identifier != identifier) continue;
}
found = true;
PluginKey key = composePluginKey(*fi, descriptor->identifier);
if (m_pluginLibraryNameMap.find(key) ==
m_pluginLibraryNameMap.end()) {
m_pluginLibraryNameMap[key] = fullPath;
}
}
if (!found && forPlugin != "") {
cerr << "Vamp::HostExt::PluginLoader: Plugin \""
<< identifier << "\" not found in library \""
<< fullPath << "\"" << endl;
}
unloadLibrary(handle);
}
}
if (forPlugin == "") m_allPluginsEnumerated = true;
}
PluginLoader::PluginKey
PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
{
string basename = libraryName;
string::size_type li = basename.rfind('/');
if (li != string::npos) basename = basename.substr(li + 1);
li = basename.find('.');
if (li != string::npos) basename = basename.substr(0, li);
for (size_t i = 0; i < basename.length(); ++i) {
basename[i] = tolower(basename[i]);
}
return basename + ":" + identifier;
}
bool
PluginLoader::Impl::decomposePluginKey(PluginKey key,
string &libraryName,
string &identifier)
{
string::size_type ki = key.find(':');
if (ki == string::npos) {
return false;
}
libraryName = key.substr(0, ki);
identifier = key.substr(ki + 1);
return true;
}
PluginLoader::PluginCategoryHierarchy
PluginLoader::Impl::getPluginCategory(PluginKey plugin)
{
if (m_taxonomy.empty()) generateTaxonomy();
if (m_taxonomy.find(plugin) == m_taxonomy.end()) {
return PluginCategoryHierarchy();
}
return m_taxonomy[plugin];
}
string
PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
{
if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
if (m_allPluginsEnumerated) return "";
enumeratePlugins(plugin);
}
if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
return "";
}
return m_pluginLibraryNameMap[plugin];
}
Plugin *
PluginLoader::Impl::loadPlugin(PluginKey key,
float inputSampleRate, int adapterFlags)
{
string libname, identifier;
if (!decomposePluginKey(key, libname, identifier)) {
std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \""
<< key << "\" in loadPlugin" << std::endl;
return 0;
}
string fullPath = getLibraryPathForPlugin(key);
if (fullPath == "") {
std::cerr << "Vamp::HostExt::PluginLoader: No library found in Vamp path for plugin \"" << key << "\"" << std::endl;
return 0;
}
void *handle = loadLibrary(fullPath);
if (!handle) return 0;
VampGetPluginDescriptorFunction fn =
(VampGetPluginDescriptorFunction)lookupInLibrary
(handle, "vampGetPluginDescriptor");
if (!fn) {
cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
<< fullPath << "\"" << endl;
unloadLibrary(handle);
return 0;
}
int index = 0;
const VampPluginDescriptor *descriptor = 0;
while ((descriptor = fn(VAMP_API_VERSION, index))) {
if (string(descriptor->identifier) == identifier) {
Vamp::PluginHostAdapter *plugin =
new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this);
m_pluginLibraryHandleMap[adapter] = handle;
if (adapterFlags & ADAPT_BUFFER_SIZE) {
PluginBufferingAdapter* a = new PluginBufferingAdapter(adapter);
adapter = a;
}
if (adapterFlags & ADAPT_INPUT_DOMAIN) {
if (adapter->getInputDomain() == Plugin::FrequencyDomain) {
adapter = new PluginInputDomainAdapter(adapter);
}
}
if (adapterFlags & ADAPT_CHANNEL_COUNT) {
adapter = new PluginChannelAdapter(adapter);
}
return adapter;
}
++index;
}
cerr << "Vamp::HostExt::PluginLoader: Plugin \""
<< identifier << "\" not found in library \""
<< fullPath << "\"" << endl;
return 0;
}
void
PluginLoader::Impl::generateTaxonomy()
{
// cerr << "PluginLoader::Impl::generateTaxonomy" << endl;
vector<string> path = PluginHostAdapter::getPluginPath();
string libfragment = "/lib/";
vector<string> catpath;
string suffix = "cat";
for (vector<string>::iterator i = path.begin();
i != path.end(); ++i) {
// It doesn't matter that we're using literal forward-slash in
// this bit, as it's only relevant if the path contains
// "/lib/", which is only meaningful and only plausible on
// systems with forward-slash delimiters
string dir = *i;
string::size_type li = dir.find(libfragment);
if (li != string::npos) {
catpath.push_back
(dir.substr(0, li)
+ "/share/"
+ dir.substr(li + libfragment.length()));
}
catpath.push_back(dir);
}
char buffer[1024];
for (vector<string>::iterator i = catpath.begin();
i != catpath.end(); ++i) {
vector<string> files = listFiles(*i, suffix);
for (vector<string>::iterator fi = files.begin();
fi != files.end(); ++fi) {
string filepath = splicePath(*i, *fi);
ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
if (is.fail()) {
// cerr << "failed to open: " << filepath << endl;
continue;
}
// cerr << "opened: " << filepath << endl;
while (!!is.getline(buffer, 1024)) {
string line(buffer);
// cerr << "line = " << line << endl;
string::size_type di = line.find("::");
if (di == string::npos) continue;
string id = line.substr(0, di);
string encodedCat = line.substr(di + 2);
if (id.substr(0, 5) != "vamp:") continue;
id = id.substr(5);
while (encodedCat.length() >= 1 &&
encodedCat[encodedCat.length()-1] == '\r') {
encodedCat = encodedCat.substr(0, encodedCat.length()-1);
}
// cerr << "id = " << id << ", cat = " << encodedCat << endl;
PluginCategoryHierarchy category;
string::size_type ai;
while ((ai = encodedCat.find(" > ")) != string::npos) {
category.push_back(encodedCat.substr(0, ai));
encodedCat = encodedCat.substr(ai + 3);
}
if (encodedCat != "") category.push_back(encodedCat);
m_taxonomy[id] = category;
}
}
}
}
void *
PluginLoader::Impl::loadLibrary(string path)
{
void *handle = 0;
#ifdef _WIN32
#ifdef UNICODE
int len = path.length(); // cannot be more wchars than length in bytes of utf8 string
wchar_t *buffer = new wchar_t[len];
int rv = MultiByteToWideChar(CP_UTF8, 0, path.c_str(), len, buffer, len);
if (rv <= 0) {
cerr << "Vamp::HostExt::PluginLoader: Unable to convert library path \""
<< path << "\" to wide characters " << endl;
delete[] buffer;
return handle;
}
handle = LoadLibrary(buffer);
delete[] buffer;
#else
handle = LoadLibrary(path.c_str());
#endif
if (!handle) {
cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
<< path << "\"" << endl;
}
#else
handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
if (!handle) {
cerr << "Vamp::HostExt::PluginLoader: Unable to load library \""
<< path << "\": " << dlerror() << endl;
}
#endif
return handle;
}
void
PluginLoader::Impl::unloadLibrary(void *handle)
{
#ifdef _WIN32
FreeLibrary((HINSTANCE)handle);
#else
dlclose(handle);
#endif
}
void *
PluginLoader::Impl::lookupInLibrary(void *handle, const char *symbol)
{
#ifdef _WIN32
return (void *)GetProcAddress((HINSTANCE)handle, symbol);
#else
return (void *)dlsym(handle, symbol);
#endif
}
string
PluginLoader::Impl::splicePath(string a, string b)
{
#ifdef _WIN32
return a + "\\" + b;
#else
return a + "/" + b;
#endif
}
vector<string>
PluginLoader::Impl::listFiles(string dir, string extension)
{
vector<string> files;
#ifdef _WIN32
string expression = dir + "\\*." + extension;
#ifdef UNICODE
int len = expression.length(); // cannot be more wchars than length in bytes of utf8 string
wchar_t *buffer = new wchar_t[len];
int rv = MultiByteToWideChar(CP_UTF8, 0, expression.c_str(), len, buffer, len);
if (rv <= 0) {
cerr << "Vamp::HostExt::PluginLoader: Unable to convert wildcard path \""
<< expression << "\" to wide characters" << endl;
delete[] buffer;
return files;
}
WIN32_FIND_DATA data;
HANDLE fh = FindFirstFile(buffer, &data);
if (fh == INVALID_HANDLE_VALUE) {
delete[] buffer;
return files;
}
bool ok = true;
while (ok) {
wchar_t *fn = data.cFileName;
int wlen = wcslen(fn);
int maxlen = wlen * 6;
char *conv = new char[maxlen];
int rv = WideCharToMultiByte(CP_UTF8, 0, fn, wlen, conv, maxlen, 0, 0);
if (rv > 0) {
files.push_back(conv);
}
delete[] conv;
ok = FindNextFile(fh, &data);
}
FindClose(fh);
delete[] buffer;
#else
WIN32_FIND_DATA data;
HANDLE fh = FindFirstFile(expression.c_str(), &data);
if (fh == INVALID_HANDLE_VALUE) return files;
bool ok = true;
while (ok) {
files.push_back(data.cFileName);
ok = FindNextFile(fh, &data);
}
FindClose(fh);
#endif
#else
size_t extlen = extension.length();
DIR *d = opendir(dir.c_str());
if (!d) return files;
struct dirent *e = 0;
while ((e = readdir(d))) {
if (!e->d_name) continue;
size_t len = strlen(e->d_name);
if (len < extlen + 2 ||
e->d_name + len - extlen - 1 != "." + extension) {
continue;
}
files.push_back(e->d_name);
}
closedir(d);
#endif
return files;
}
void
PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
{
void *handle = m_pluginLibraryHandleMap[adapter];
if (handle) unloadLibrary(handle);
m_pluginLibraryHandleMap.erase(adapter);
}
PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
Impl *loader) :
PluginWrapper(plugin),
m_loader(loader)
{
}
PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
{
// We need to delete the plugin before calling pluginDeleted, as
// the delete call may require calling through to the descriptor
// (for e.g. cleanup) but pluginDeleted may unload the required
// library for the call. To prevent a double deletion when our
// parent's destructor runs (after this one), be sure to set
// m_plugin to 0 after deletion.
delete m_plugin;
m_plugin = 0;
if (m_loader) m_loader->pluginDeleted(this);
}
}
}
_VAMP_SDK_HOSTSPACE_END(PluginLoader.cpp)

View File

@@ -1,952 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include "vamp-hostsdk/PluginSummarisingAdapter.h"
#include <map>
#include <algorithm>
#include <cmath>
#include <climits>
//#define DEBUG_PLUGIN_SUMMARISING_ADAPTER 1
//#define DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT 1
_VAMP_SDK_HOSTSPACE_BEGIN(PluginSummarisingAdapter.cpp)
namespace Vamp {
namespace HostExt {
class PluginSummarisingAdapter::Impl
{
public:
Impl(Plugin *plugin, float inputSampleRate);
~Impl();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures();
void setSummarySegmentBoundaries(const SegmentBoundaries &);
FeatureList getSummaryForOutput(int output,
SummaryType type,
AveragingMethod avg);
FeatureSet getSummaryForAllOutputs(SummaryType type,
AveragingMethod avg);
protected:
Plugin *m_plugin;
float m_inputSampleRate;
size_t m_stepSize;
size_t m_blockSize;
SegmentBoundaries m_boundaries;
typedef std::vector<float> ValueList;
struct Result { // smaller than Feature
RealTime time;
RealTime duration;
ValueList values; // bin number -> value
};
typedef std::vector<Result> ResultList;
struct OutputAccumulator {
int bins;
ResultList results;
OutputAccumulator() : bins(0) { }
};
typedef std::map<int, OutputAccumulator> OutputAccumulatorMap;
OutputAccumulatorMap m_accumulators; // output number -> accumulator
typedef std::map<RealTime, OutputAccumulator> SegmentAccumulatorMap;
typedef std::map<int, SegmentAccumulatorMap> OutputSegmentAccumulatorMap;
OutputSegmentAccumulatorMap m_segmentedAccumulators; // output -> segmented
typedef std::map<int, RealTime> OutputTimestampMap;
OutputTimestampMap m_prevTimestamps; // output number -> timestamp
OutputTimestampMap m_prevDurations; // output number -> durations
struct OutputBinSummary {
int count;
// extents
double minimum;
double maximum;
double sum;
// sample-average results
double median;
double mode;
double variance;
// continuous-time average results
double median_c;
double mode_c;
double mean_c;
double variance_c;
};
typedef std::map<int, OutputBinSummary> OutputSummary;
typedef std::map<RealTime, OutputSummary> SummarySegmentMap;
typedef std::map<int, SummarySegmentMap> OutputSummarySegmentMap;
OutputSummarySegmentMap m_summaries;
bool m_reduced;
RealTime m_endTime;
void accumulate(const FeatureSet &fs, RealTime, bool final);
void accumulate(int output, const Feature &f, RealTime, bool final);
void accumulateFinalDurations();
void findSegmentBounds(RealTime t, RealTime &start, RealTime &end);
void segment();
void reduce();
std::string getSummaryLabel(SummaryType type, AveragingMethod avg);
};
static RealTime INVALID_DURATION(INT_MIN, INT_MIN);
PluginSummarisingAdapter::PluginSummarisingAdapter(Plugin *plugin) :
PluginWrapper(plugin)
{
m_impl = new Impl(plugin, m_inputSampleRate);
}
PluginSummarisingAdapter::~PluginSummarisingAdapter()
{
delete m_impl;
}
bool
PluginSummarisingAdapter::initialise(size_t channels,
size_t stepSize, size_t blockSize)
{
return
PluginWrapper::initialise(channels, stepSize, blockSize) &&
m_impl->initialise(channels, stepSize, blockSize);
}
void
PluginSummarisingAdapter::reset()
{
m_impl->reset();
}
Plugin::FeatureSet
PluginSummarisingAdapter::process(const float *const *inputBuffers, RealTime timestamp)
{
return m_impl->process(inputBuffers, timestamp);
}
Plugin::FeatureSet
PluginSummarisingAdapter::getRemainingFeatures()
{
return m_impl->getRemainingFeatures();
}
void
PluginSummarisingAdapter::setSummarySegmentBoundaries(const SegmentBoundaries &b)
{
m_impl->setSummarySegmentBoundaries(b);
}
Plugin::FeatureList
PluginSummarisingAdapter::getSummaryForOutput(int output,
SummaryType type,
AveragingMethod avg)
{
return m_impl->getSummaryForOutput(output, type, avg);
}
Plugin::FeatureSet
PluginSummarisingAdapter::getSummaryForAllOutputs(SummaryType type,
AveragingMethod avg)
{
return m_impl->getSummaryForAllOutputs(type, avg);
}
PluginSummarisingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
m_plugin(plugin),
m_inputSampleRate(inputSampleRate),
m_reduced(false)
{
}
PluginSummarisingAdapter::Impl::~Impl()
{
}
bool
PluginSummarisingAdapter::Impl::initialise(size_t channels,
size_t stepSize, size_t blockSize)
{
m_stepSize = stepSize;
m_blockSize = blockSize;
return true;
}
void
PluginSummarisingAdapter::Impl::reset()
{
m_accumulators.clear();
m_segmentedAccumulators.clear();
m_prevTimestamps.clear();
m_prevDurations.clear();
m_summaries.clear();
m_reduced = false;
m_endTime = RealTime();
m_plugin->reset();
}
Plugin::FeatureSet
PluginSummarisingAdapter::Impl::process(const float *const *inputBuffers,
RealTime timestamp)
{
if (m_reduced) {
std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl;
}
FeatureSet fs = m_plugin->process(inputBuffers, timestamp);
accumulate(fs, timestamp, false);
m_endTime = timestamp +
RealTime::frame2RealTime(m_stepSize, int(m_inputSampleRate + 0.5));
return fs;
}
Plugin::FeatureSet
PluginSummarisingAdapter::Impl::getRemainingFeatures()
{
if (m_reduced) {
std::cerr << "WARNING: Cannot call PluginSummarisingAdapter::process() or getRemainingFeatures() after one of the getSummary methods" << std::endl;
}
FeatureSet fs = m_plugin->getRemainingFeatures();
accumulate(fs, m_endTime, true);
return fs;
}
void
PluginSummarisingAdapter::Impl::setSummarySegmentBoundaries(const SegmentBoundaries &b)
{
m_boundaries = b;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "PluginSummarisingAdapter::setSummarySegmentBoundaries: boundaries are:" << std::endl;
for (SegmentBoundaries::const_iterator i = m_boundaries.begin();
i != m_boundaries.end(); ++i) {
std::cerr << *i << " ";
}
std::cerr << std::endl;
#endif
}
Plugin::FeatureList
PluginSummarisingAdapter::Impl::getSummaryForOutput(int output,
SummaryType type,
AveragingMethod avg)
{
if (!m_reduced) {
accumulateFinalDurations();
segment();
reduce();
m_reduced = true;
}
bool continuous = (avg == ContinuousTimeAverage);
FeatureList fl;
for (SummarySegmentMap::const_iterator i = m_summaries[output].begin();
i != m_summaries[output].end(); ++i) {
Feature f;
f.hasTimestamp = true;
f.timestamp = i->first;
f.hasDuration = true;
SummarySegmentMap::const_iterator ii = i;
if (++ii == m_summaries[output].end()) {
f.duration = m_endTime - f.timestamp;
} else {
f.duration = ii->first - f.timestamp;
}
f.label = getSummaryLabel(type, avg);
for (OutputSummary::const_iterator j = i->second.begin();
j != i->second.end(); ++j) {
// these will be ordered by bin number, and no bin numbers
// will be missing except at the end (because of the way
// the accumulators were initially filled in accumulate())
const OutputBinSummary &summary = j->second;
double result = 0.f;
switch (type) {
case Minimum:
result = summary.minimum;
break;
case Maximum:
result = summary.maximum;
break;
case Mean:
if (continuous) {
result = summary.mean_c;
} else if (summary.count) {
result = summary.sum / summary.count;
}
break;
case Median:
if (continuous) result = summary.median_c;
else result = summary.median;
break;
case Mode:
if (continuous) result = summary.mode_c;
else result = summary.mode;
break;
case Sum:
result = summary.sum;
break;
case Variance:
if (continuous) result = summary.variance_c;
else result = summary.variance;
break;
case StandardDeviation:
if (continuous) result = sqrtf(summary.variance_c);
else result = sqrtf(summary.variance);
break;
case Count:
result = summary.count;
break;
case UnknownSummaryType:
break;
default:
break;
}
f.values.push_back(result);
}
fl.push_back(f);
}
return fl;
}
Plugin::FeatureSet
PluginSummarisingAdapter::Impl::getSummaryForAllOutputs(SummaryType type,
AveragingMethod avg)
{
if (!m_reduced) {
accumulateFinalDurations();
segment();
reduce();
m_reduced = true;
}
FeatureSet fs;
for (OutputSummarySegmentMap::const_iterator i = m_summaries.begin();
i != m_summaries.end(); ++i) {
fs[i->first] = getSummaryForOutput(i->first, type, avg);
}
return fs;
}
void
PluginSummarisingAdapter::Impl::accumulate(const FeatureSet &fs,
RealTime timestamp,
bool final)
{
for (FeatureSet::const_iterator i = fs.begin(); i != fs.end(); ++i) {
for (FeatureList::const_iterator j = i->second.begin();
j != i->second.end(); ++j) {
if (j->hasTimestamp) {
accumulate(i->first, *j, j->timestamp, final);
} else {
//!!! is this correct?
accumulate(i->first, *j, timestamp, final);
}
}
}
}
std::string
PluginSummarisingAdapter::Impl::getSummaryLabel(SummaryType type,
AveragingMethod avg)
{
std::string label;
std::string avglabel;
if (avg == SampleAverage) avglabel = ", sample average";
else avglabel = ", continuous-time average";
switch (type) {
case Minimum: label = "(minimum value)"; break;
case Maximum: label = "(maximum value)"; break;
case Mean: label = "(mean value" + avglabel + ")"; break;
case Median: label = "(median value" + avglabel + ")"; break;
case Mode: label = "(modal value" + avglabel + ")"; break;
case Sum: label = "(sum)"; break;
case Variance: label = "(variance" + avglabel + ")"; break;
case StandardDeviation: label = "(standard deviation" + avglabel + ")"; break;
case Count: label = "(count)"; break;
case UnknownSummaryType: label = "(unknown summary)"; break;
}
return label;
}
void
PluginSummarisingAdapter::Impl::accumulate(int output,
const Feature &f,
RealTime timestamp,
bool final)
{
// What should happen if a feature's duration spans a segment
// boundary? I think we probably want to chop it, and pretend
// that it appears in both. A very long feature (e.g. key, if the
// whole audio is in a single key) might span many or all
// segments, and we want that to be reflected in the results
// (e.g. it is the modal key in all of those segments, not just
// the first). This is actually quite complicated to do.
// If features spanning a boundary should be chopped, then we need
// to have per-segment accumulators (and the feature value goes
// into both -- with a separate phase to split the accumulator up
// into segments).
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "output " << output << ": timestamp " << timestamp << ", prev timestamp " << m_prevTimestamps[output] << ", final " << final << std::endl;
#endif
// At each process step, accumulate() is called once for each
// feature on each output within that process's returned feature
// list, and with the timestamp passed in being that of the start
// of the process block.
// At the end (in getRemainingFeatures), accumulate() is called
// once for each feature on each output within the feature list
// returned by getRemainingFeatures, and with the timestamp being
// the same as the last process block and final set to true.
// (What if getRemainingFeatures doesn't return any features? We
// still need to ensure that the final duration is written. Need
// a separate function to close the durations.)
// At each call, we pull out the value for the feature and stuff
// it into the accumulator's appropriate values array; and we
// calculate the duration for the _previous_ feature, or pull it
// from the prevDurations array if the previous feature had a
// duration in its structure, and stuff that into the
// accumulator's appropriate durations array.
if (m_prevDurations.find(output) != m_prevDurations.end()) {
// Not the first time accumulate has been called for this
// output -- there has been a previous feature
RealTime prevDuration;
// Note that m_prevDurations[output] only contains the
// duration field that was contained in the previous feature.
// If it didn't have an explicit duration,
// m_prevDurations[output] should be INVALID_DURATION and we
// will have to calculate the duration from the previous and
// current timestamps.
if (m_prevDurations[output] != INVALID_DURATION) {
prevDuration = m_prevDurations[output];
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "Previous duration from previous feature: " << prevDuration << std::endl;
#endif
} else {
prevDuration = timestamp - m_prevTimestamps[output];
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "Previous duration from diff: " << timestamp << " - "
<< m_prevTimestamps[output] << std::endl;
#endif
}
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "output " << output << ": ";
std::cerr << "Pushing previous duration as " << prevDuration << std::endl;
#endif
m_accumulators[output].results
[m_accumulators[output].results.size() - 1]
.duration = prevDuration;
}
if (f.hasDuration) m_prevDurations[output] = f.duration;
else m_prevDurations[output] = INVALID_DURATION;
m_prevTimestamps[output] = timestamp;
if (f.hasDuration) {
RealTime et = timestamp;
et = et + f.duration;
if (et > m_endTime) m_endTime = et;
}
Result result;
result.time = timestamp;
result.duration = INVALID_DURATION;
if (int(f.values.size()) > m_accumulators[output].bins) {
m_accumulators[output].bins = f.values.size();
}
for (int i = 0; i < int(f.values.size()); ++i) {
result.values.push_back(f.values[i]);
}
m_accumulators[output].results.push_back(result);
}
void
PluginSummarisingAdapter::Impl::accumulateFinalDurations()
{
for (OutputTimestampMap::iterator i = m_prevTimestamps.begin();
i != m_prevTimestamps.end(); ++i) {
int output = i->first;
int acount = m_accumulators[output].results.size();
if (acount == 0) continue;
RealTime prevTimestamp = i->second;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "output " << output << ": ";
#endif
if (m_prevDurations.find(output) != m_prevDurations.end() &&
m_prevDurations[output] != INVALID_DURATION) {
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "Pushing final duration from feature as " << m_prevDurations[output] << std::endl;
#endif
m_accumulators[output].results[acount - 1].duration =
m_prevDurations[output];
} else {
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "Pushing final duration from diff as " << m_endTime << " - " << m_prevTimestamps[output] << std::endl;
#endif
m_accumulators[output].results[acount - 1].duration =
m_endTime - m_prevTimestamps[output];
}
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "so duration for result no " << acount-1 << " is "
<< m_accumulators[output].results[acount-1].duration
<< std::endl;
#endif
}
}
void
PluginSummarisingAdapter::Impl::findSegmentBounds(RealTime t,
RealTime &start,
RealTime &end)
{
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "findSegmentBounds: t = " << t << std::endl;
#endif
SegmentBoundaries::const_iterator i = std::upper_bound
(m_boundaries.begin(), m_boundaries.end(), t);
start = RealTime::zeroTime;
end = m_endTime;
if (i != m_boundaries.end()) {
end = *i;
}
if (i != m_boundaries.begin()) {
start = *--i;
}
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "findSegmentBounds: " << t << " is in segment " << start << " -> " << end << std::endl;
#endif
}
void
PluginSummarisingAdapter::Impl::segment()
{
SegmentBoundaries::iterator boundaryitr = m_boundaries.begin();
RealTime segmentStart = RealTime::zeroTime;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "segment: starting" << std::endl;
#endif
for (OutputAccumulatorMap::iterator i = m_accumulators.begin();
i != m_accumulators.end(); ++i) {
int output = i->first;
OutputAccumulator &source = i->second;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "segment: total results for output " << output << " = "
<< source.results.size() << std::endl;
#endif
// This is basically nonsense if the results have no values
// (i.e. their times and counts are the only things of
// interest)... but perhaps it's the user's problem if they
// ask for segmentation (or any summary at all) in that case
for (int n = 0; n < int(source.results.size()); ++n) {
// This result spans source.results[n].time to
// source.results[n].time + source.results[n].duration.
// We need to dispose it into segments appropriately
RealTime resultStart = source.results[n].time;
RealTime resultEnd = resultStart + source.results[n].duration;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "output: " << output << ", result start = " << resultStart << ", end = " << resultEnd << std::endl;
#endif
RealTime segmentStart = RealTime::zeroTime;
RealTime segmentEnd = resultEnd - RealTime(1, 0);
RealTime prevSegmentStart = segmentStart - RealTime(1, 0);
while (segmentEnd < resultEnd) {
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "segment end " << segmentEnd << " < result end "
<< resultEnd << " (with result start " << resultStart << ")" << std::endl;
#endif
findSegmentBounds(resultStart, segmentStart, segmentEnd);
if (segmentStart == prevSegmentStart) {
// This can happen when we reach the end of the
// input, if a feature's end time overruns the
// input audio end time
break;
}
prevSegmentStart = segmentStart;
RealTime chunkStart = resultStart;
if (chunkStart < segmentStart) chunkStart = segmentStart;
RealTime chunkEnd = resultEnd;
if (chunkEnd > segmentEnd) chunkEnd = segmentEnd;
m_segmentedAccumulators[output][segmentStart].bins = source.bins;
Result chunk;
chunk.time = chunkStart;
chunk.duration = chunkEnd - chunkStart;
chunk.values = source.results[n].values;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER_SEGMENT
std::cerr << "chunk for segment " << segmentStart << ": from " << chunk.time << ", duration " << chunk.duration << std::endl;
#endif
m_segmentedAccumulators[output][segmentStart].results
.push_back(chunk);
resultStart = chunkEnd;
}
}
}
}
struct ValueDurationFloatPair
{
float value;
float duration;
ValueDurationFloatPair() : value(0), duration(0) { }
ValueDurationFloatPair(float v, float d) : value(v), duration(d) { }
ValueDurationFloatPair &operator=(const ValueDurationFloatPair &p) {
value = p.value;
duration = p.duration;
return *this;
}
bool operator<(const ValueDurationFloatPair &p) const {
return value < p.value;
}
};
static double toSec(const RealTime &r)
{
return r.sec + double(r.nsec) / 1000000000.0;
}
void
PluginSummarisingAdapter::Impl::reduce()
{
for (OutputSegmentAccumulatorMap::iterator i =
m_segmentedAccumulators.begin();
i != m_segmentedAccumulators.end(); ++i) {
int output = i->first;
SegmentAccumulatorMap &segments = i->second;
for (SegmentAccumulatorMap::iterator j = segments.begin();
j != segments.end(); ++j) {
RealTime segmentStart = j->first;
OutputAccumulator &accumulator = j->second;
int sz = accumulator.results.size();
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "reduce: segment starting at " << segmentStart
<< " on output " << output << " has " << sz << " result(s)" << std::endl;
#endif
double totalDuration = 0.0;
//!!! is this right?
if (sz > 0) {
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "last time = " << accumulator.results[sz-1].time
<< ", duration = " << accumulator.results[sz-1].duration
<< " (step = " << m_stepSize << ", block = " << m_blockSize << ")"
<< std::endl;
#endif
totalDuration = toSec((accumulator.results[sz-1].time +
accumulator.results[sz-1].duration) -
segmentStart);
}
for (int bin = 0; bin < accumulator.bins; ++bin) {
// work on all values over time for a single bin
OutputBinSummary summary;
summary.count = sz;
summary.minimum = 0.f;
summary.maximum = 0.f;
summary.median = 0.f;
summary.mode = 0.f;
summary.sum = 0.f;
summary.variance = 0.f;
summary.median_c = 0.f;
summary.mode_c = 0.f;
summary.mean_c = 0.f;
summary.variance_c = 0.f;
if (sz == 0) continue;
std::vector<ValueDurationFloatPair> valvec;
for (int k = 0; k < sz; ++k) {
while (int(accumulator.results[k].values.size()) <
accumulator.bins) {
accumulator.results[k].values.push_back(0.f);
}
}
for (int k = 0; k < sz; ++k) {
float value = accumulator.results[k].values[bin];
valvec.push_back(ValueDurationFloatPair
(value,
toSec(accumulator.results[k].duration)));
}
std::sort(valvec.begin(), valvec.end());
summary.minimum = valvec[0].value;
summary.maximum = valvec[sz-1].value;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "total duration = " << totalDuration << std::endl;
#endif
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
/*
std::cerr << "value vector for medians:" << std::endl;
for (int k = 0; k < sz; ++k) {
std::cerr << "(" << valvec[k].value << "," << valvec[k].duration << ") ";
}
std::cerr << std::endl;
*/
#endif
if (sz % 2 == 1) {
summary.median = valvec[sz/2].value;
} else {
summary.median = (valvec[sz/2].value + valvec[sz/2 + 1].value) / 2;
}
double duracc = 0.0;
summary.median_c = valvec[sz-1].value;
for (int k = 0; k < sz; ++k) {
duracc += valvec[k].duration;
if (duracc > totalDuration/2) {
summary.median_c = valvec[k].value;
break;
}
}
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "median_c = " << summary.median_c << std::endl;
std::cerr << "median = " << summary.median << std::endl;
#endif
std::map<float, int> distribution;
for (int k = 0; k < sz; ++k) {
summary.sum += accumulator.results[k].values[bin];
distribution[accumulator.results[k].values[bin]] += 1;
}
int md = 0;
for (std::map<float, int>::iterator di = distribution.begin();
di != distribution.end(); ++di) {
if (di->second > md) {
md = di->second;
summary.mode = di->first;
}
}
distribution.clear();
std::map<float, double> distribution_c;
for (int k = 0; k < sz; ++k) {
distribution_c[accumulator.results[k].values[bin]]
+= toSec(accumulator.results[k].duration);
}
double mrd = 0.0;
for (std::map<float, double>::iterator di = distribution_c.begin();
di != distribution_c.end(); ++di) {
if (di->second > mrd) {
mrd = di->second;
summary.mode_c = di->first;
}
}
distribution_c.clear();
if (totalDuration > 0.0) {
double sum_c = 0.0;
for (int k = 0; k < sz; ++k) {
double value = accumulator.results[k].values[bin]
* toSec(accumulator.results[k].duration);
sum_c += value;
}
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "mean_c = " << sum_c << " / " << totalDuration << " = "
<< sum_c / totalDuration << " (sz = " << sz << ")" << std::endl;
#endif
summary.mean_c = sum_c / totalDuration;
for (int k = 0; k < sz; ++k) {
double value = accumulator.results[k].values[bin];
// * toSec(accumulator.results[k].duration);
summary.variance_c +=
(value - summary.mean_c) * (value - summary.mean_c)
* toSec(accumulator.results[k].duration);
}
// summary.variance_c /= summary.count;
summary.variance_c /= totalDuration;
}
double mean = summary.sum / summary.count;
#ifdef DEBUG_PLUGIN_SUMMARISING_ADAPTER
std::cerr << "mean = " << summary.sum << " / " << summary.count << " = "
<< summary.sum / summary.count << std::endl;
#endif
for (int k = 0; k < sz; ++k) {
float value = accumulator.results[k].values[bin];
summary.variance += (value - mean) * (value - mean);
}
summary.variance /= summary.count;
m_summaries[output][segmentStart][bin] = summary;
}
}
}
m_segmentedAccumulators.clear();
m_accumulators.clear();
}
}
}
_VAMP_SDK_HOSTSPACE_END(PluginSummarisingAdapter.cpp)

View File

@@ -1,204 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include "vamp-hostsdk/PluginWrapper.h"
_VAMP_SDK_HOSTSPACE_BEGIN(PluginWrapper.cpp)
namespace Vamp {
namespace HostExt {
class PluginRateExtractor : public Plugin
{
public:
PluginRateExtractor() : Plugin(0) { }
float getRate() const { return m_inputSampleRate; }
};
PluginWrapper::PluginWrapper(Plugin *plugin) :
Plugin(((PluginRateExtractor *)plugin)->getRate()),
m_plugin(plugin)
{
}
PluginWrapper::~PluginWrapper()
{
delete m_plugin;
}
bool
PluginWrapper::initialise(size_t channels, size_t stepSize, size_t blockSize)
{
return m_plugin->initialise(channels, stepSize, blockSize);
}
void
PluginWrapper::reset()
{
m_plugin->reset();
}
Plugin::InputDomain
PluginWrapper::getInputDomain() const
{
return m_plugin->getInputDomain();
}
unsigned int
PluginWrapper::getVampApiVersion() const
{
return m_plugin->getVampApiVersion();
}
std::string
PluginWrapper::getIdentifier() const
{
return m_plugin->getIdentifier();
}
std::string
PluginWrapper::getName() const
{
return m_plugin->getName();
}
std::string
PluginWrapper::getDescription() const
{
return m_plugin->getDescription();
}
std::string
PluginWrapper::getMaker() const
{
return m_plugin->getMaker();
}
int
PluginWrapper::getPluginVersion() const
{
return m_plugin->getPluginVersion();
}
std::string
PluginWrapper::getCopyright() const
{
return m_plugin->getCopyright();
}
PluginBase::ParameterList
PluginWrapper::getParameterDescriptors() const
{
return m_plugin->getParameterDescriptors();
}
float
PluginWrapper::getParameter(std::string parameter) const
{
return m_plugin->getParameter(parameter);
}
void
PluginWrapper::setParameter(std::string parameter, float value)
{
m_plugin->setParameter(parameter, value);
}
PluginBase::ProgramList
PluginWrapper::getPrograms() const
{
return m_plugin->getPrograms();
}
std::string
PluginWrapper::getCurrentProgram() const
{
return m_plugin->getCurrentProgram();
}
void
PluginWrapper::selectProgram(std::string program)
{
m_plugin->selectProgram(program);
}
size_t
PluginWrapper::getPreferredStepSize() const
{
return m_plugin->getPreferredStepSize();
}
size_t
PluginWrapper::getPreferredBlockSize() const
{
return m_plugin->getPreferredBlockSize();
}
size_t
PluginWrapper::getMinChannelCount() const
{
return m_plugin->getMinChannelCount();
}
size_t PluginWrapper::getMaxChannelCount() const
{
return m_plugin->getMaxChannelCount();
}
Plugin::OutputList
PluginWrapper::getOutputDescriptors() const
{
return m_plugin->getOutputDescriptors();
}
Plugin::FeatureSet
PluginWrapper::process(const float *const *inputBuffers, RealTime timestamp)
{
return m_plugin->process(inputBuffers, timestamp);
}
Plugin::FeatureSet
PluginWrapper::getRemainingFeatures()
{
return m_plugin->getRemainingFeatures();
}
}
}
_VAMP_SDK_HOSTSPACE_END(PluginWrapper.cpp)

View File

@@ -1,39 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include "vamp-hostsdk/RealTime.h"
#include "../vamp-sdk/RealTime.cpp"

View File

@@ -1,919 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#include "vamp-sdk/PluginAdapter.h"
#include <cstring>
#include <cstdlib>
#if ( VAMP_SDK_MAJOR_VERSION != 2 || VAMP_SDK_MINOR_VERSION != 2 )
#error Unexpected version of Vamp SDK header included
#endif
//#define DEBUG_PLUGIN_ADAPTER 1
_VAMP_SDK_PLUGSPACE_BEGIN(PluginAdapter.cpp)
namespace Vamp {
class PluginAdapterBase::Impl
{
public:
Impl(PluginAdapterBase *);
~Impl();
const VampPluginDescriptor *getDescriptor();
protected:
PluginAdapterBase *m_base;
static VampPluginHandle vampInstantiate(const VampPluginDescriptor *desc,
float inputSampleRate);
static void vampCleanup(VampPluginHandle handle);
static int vampInitialise(VampPluginHandle handle, unsigned int channels,
unsigned int stepSize, unsigned int blockSize);
static void vampReset(VampPluginHandle handle);
static float vampGetParameter(VampPluginHandle handle, int param);
static void vampSetParameter(VampPluginHandle handle, int param, float value);
static unsigned int vampGetCurrentProgram(VampPluginHandle handle);
static void vampSelectProgram(VampPluginHandle handle, unsigned int program);
static unsigned int vampGetPreferredStepSize(VampPluginHandle handle);
static unsigned int vampGetPreferredBlockSize(VampPluginHandle handle);
static unsigned int vampGetMinChannelCount(VampPluginHandle handle);
static unsigned int vampGetMaxChannelCount(VampPluginHandle handle);
static unsigned int vampGetOutputCount(VampPluginHandle handle);
static VampOutputDescriptor *vampGetOutputDescriptor(VampPluginHandle handle,
unsigned int i);
static void vampReleaseOutputDescriptor(VampOutputDescriptor *desc);
static VampFeatureList *vampProcess(VampPluginHandle handle,
const float *const *inputBuffers,
int sec,
int nsec);
static VampFeatureList *vampGetRemainingFeatures(VampPluginHandle handle);
static void vampReleaseFeatureSet(VampFeatureList *fs);
void checkOutputMap(Plugin *plugin);
void markOutputsChanged(Plugin *plugin);
void cleanup(Plugin *plugin);
unsigned int getOutputCount(Plugin *plugin);
VampOutputDescriptor *getOutputDescriptor(Plugin *plugin,
unsigned int i);
VampFeatureList *process(Plugin *plugin,
const float *const *inputBuffers,
int sec, int nsec);
VampFeatureList *getRemainingFeatures(Plugin *plugin);
VampFeatureList *convertFeatures(Plugin *plugin,
const Plugin::FeatureSet &features);
// maps both plugins and descriptors to adapters
typedef std::map<const void *, Impl *> AdapterMap;
static AdapterMap *m_adapterMap;
static Impl *lookupAdapter(VampPluginHandle);
bool m_populated;
VampPluginDescriptor m_descriptor;
Plugin::ParameterList m_parameters;
Plugin::ProgramList m_programs;
typedef std::map<Plugin *, Plugin::OutputList *> OutputMap;
OutputMap m_pluginOutputs;
std::map<Plugin *, VampFeatureList *> m_fs;
std::map<Plugin *, std::vector<size_t> > m_fsizes;
std::map<Plugin *, std::vector<std::vector<size_t> > > m_fvsizes;
void resizeFS(Plugin *plugin, int n);
void resizeFL(Plugin *plugin, int n, size_t sz);
void resizeFV(Plugin *plugin, int n, int j, size_t sz);
};
PluginAdapterBase::PluginAdapterBase()
{
m_impl = new Impl(this);
}
PluginAdapterBase::~PluginAdapterBase()
{
delete m_impl;
}
const VampPluginDescriptor *
PluginAdapterBase::getDescriptor()
{
return m_impl->getDescriptor();
}
PluginAdapterBase::Impl::Impl(PluginAdapterBase *base) :
m_base(base),
m_populated(false)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl[" << this << "]::Impl" << std::endl;
#endif
}
const VampPluginDescriptor *
PluginAdapterBase::Impl::getDescriptor()
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl[" << this << "]::getDescriptor" << std::endl;
#endif
if (m_populated) return &m_descriptor;
Plugin *plugin = m_base->createPlugin(48000);
if (!plugin) {
std::cerr << "PluginAdapterBase::Impl::getDescriptor: Failed to create plugin" << std::endl;
return 0;
}
if (plugin->getVampApiVersion() != VAMP_API_VERSION) {
std::cerr << "Vamp::PluginAdapterBase::Impl::getDescriptor: ERROR: "
<< "API version " << plugin->getVampApiVersion()
<< " for\nplugin \"" << plugin->getIdentifier() << "\" "
<< "differs from version "
<< VAMP_API_VERSION << " for adapter.\n"
<< "This plugin is probably linked against a different version of the Vamp SDK\n"
<< "from the version it was compiled with. It will need to be re-linked correctly\n"
<< "before it can be used." << std::endl;
delete plugin;
return 0;
}
m_parameters = plugin->getParameterDescriptors();
m_programs = plugin->getPrograms();
m_descriptor.vampApiVersion = plugin->getVampApiVersion();
m_descriptor.identifier = strdup(plugin->getIdentifier().c_str());
m_descriptor.name = strdup(plugin->getName().c_str());
m_descriptor.description = strdup(plugin->getDescription().c_str());
m_descriptor.maker = strdup(plugin->getMaker().c_str());
m_descriptor.pluginVersion = plugin->getPluginVersion();
m_descriptor.copyright = strdup(plugin->getCopyright().c_str());
m_descriptor.parameterCount = m_parameters.size();
m_descriptor.parameters = (const VampParameterDescriptor **)
malloc(m_parameters.size() * sizeof(VampParameterDescriptor));
unsigned int i;
for (i = 0; i < m_parameters.size(); ++i) {
VampParameterDescriptor *desc = (VampParameterDescriptor *)
malloc(sizeof(VampParameterDescriptor));
desc->identifier = strdup(m_parameters[i].identifier.c_str());
desc->name = strdup(m_parameters[i].name.c_str());
desc->description = strdup(m_parameters[i].description.c_str());
desc->unit = strdup(m_parameters[i].unit.c_str());
desc->minValue = m_parameters[i].minValue;
desc->maxValue = m_parameters[i].maxValue;
desc->defaultValue = m_parameters[i].defaultValue;
desc->isQuantized = m_parameters[i].isQuantized;
desc->quantizeStep = m_parameters[i].quantizeStep;
desc->valueNames = 0;
if (desc->isQuantized && !m_parameters[i].valueNames.empty()) {
desc->valueNames = (const char **)
malloc((m_parameters[i].valueNames.size()+1) * sizeof(char *));
for (unsigned int j = 0; j < m_parameters[i].valueNames.size(); ++j) {
desc->valueNames[j] = strdup(m_parameters[i].valueNames[j].c_str());
}
desc->valueNames[m_parameters[i].valueNames.size()] = 0;
}
m_descriptor.parameters[i] = desc;
}
m_descriptor.programCount = m_programs.size();
m_descriptor.programs = (const char **)
malloc(m_programs.size() * sizeof(const char *));
for (i = 0; i < m_programs.size(); ++i) {
m_descriptor.programs[i] = strdup(m_programs[i].c_str());
}
if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
m_descriptor.inputDomain = vampFrequencyDomain;
} else {
m_descriptor.inputDomain = vampTimeDomain;
}
m_descriptor.instantiate = vampInstantiate;
m_descriptor.cleanup = vampCleanup;
m_descriptor.initialise = vampInitialise;
m_descriptor.reset = vampReset;
m_descriptor.getParameter = vampGetParameter;
m_descriptor.setParameter = vampSetParameter;
m_descriptor.getCurrentProgram = vampGetCurrentProgram;
m_descriptor.selectProgram = vampSelectProgram;
m_descriptor.getPreferredStepSize = vampGetPreferredStepSize;
m_descriptor.getPreferredBlockSize = vampGetPreferredBlockSize;
m_descriptor.getMinChannelCount = vampGetMinChannelCount;
m_descriptor.getMaxChannelCount = vampGetMaxChannelCount;
m_descriptor.getOutputCount = vampGetOutputCount;
m_descriptor.getOutputDescriptor = vampGetOutputDescriptor;
m_descriptor.releaseOutputDescriptor = vampReleaseOutputDescriptor;
m_descriptor.process = vampProcess;
m_descriptor.getRemainingFeatures = vampGetRemainingFeatures;
m_descriptor.releaseFeatureSet = vampReleaseFeatureSet;
if (!m_adapterMap) {
m_adapterMap = new AdapterMap;
}
(*m_adapterMap)[&m_descriptor] = this;
delete plugin;
m_populated = true;
return &m_descriptor;
}
PluginAdapterBase::Impl::~Impl()
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl[" << this << "]::~Impl" << std::endl;
#endif
if (!m_populated) return;
free((void *)m_descriptor.identifier);
free((void *)m_descriptor.name);
free((void *)m_descriptor.description);
free((void *)m_descriptor.maker);
free((void *)m_descriptor.copyright);
for (unsigned int i = 0; i < m_descriptor.parameterCount; ++i) {
const VampParameterDescriptor *desc = m_descriptor.parameters[i];
free((void *)desc->identifier);
free((void *)desc->name);
free((void *)desc->description);
free((void *)desc->unit);
if (desc->valueNames) {
for (unsigned int j = 0; desc->valueNames[j]; ++j) {
free((void *)desc->valueNames[j]);
}
free((void *)desc->valueNames);
}
}
free((void *)m_descriptor.parameters);
for (unsigned int i = 0; i < m_descriptor.programCount; ++i) {
free((void *)m_descriptor.programs[i]);
}
free((void *)m_descriptor.programs);
if (m_adapterMap) {
m_adapterMap->erase(&m_descriptor);
if (m_adapterMap->empty()) {
delete m_adapterMap;
m_adapterMap = 0;
}
}
}
PluginAdapterBase::Impl *
PluginAdapterBase::Impl::lookupAdapter(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::lookupAdapter(" << handle << ")" << std::endl;
#endif
if (!m_adapterMap) return 0;
AdapterMap::const_iterator i = m_adapterMap->find(handle);
if (i == m_adapterMap->end()) return 0;
return i->second;
}
VampPluginHandle
PluginAdapterBase::Impl::vampInstantiate(const VampPluginDescriptor *desc,
float inputSampleRate)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << ")" << std::endl;
#endif
if (!m_adapterMap) {
m_adapterMap = new AdapterMap();
}
if (m_adapterMap->find(desc) == m_adapterMap->end()) {
std::cerr << "WARNING: PluginAdapterBase::Impl::vampInstantiate: Descriptor " << desc << " not in adapter map" << std::endl;
return 0;
}
Impl *adapter = (*m_adapterMap)[desc];
if (desc != &adapter->m_descriptor) return 0;
Plugin *plugin = adapter->m_base->createPlugin(inputSampleRate);
if (plugin) {
(*m_adapterMap)[plugin] = adapter;
}
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << "): returning handle " << plugin << std::endl;
#endif
return plugin;
}
void
PluginAdapterBase::Impl::vampCleanup(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampCleanup(" << handle << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) {
delete ((Plugin *)handle);
return;
}
adapter->cleanup(((Plugin *)handle));
}
int
PluginAdapterBase::Impl::vampInitialise(VampPluginHandle handle,
unsigned int channels,
unsigned int stepSize,
unsigned int blockSize)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampInitialise(" << handle << ", " << channels << ", " << stepSize << ", " << blockSize << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0;
bool result = ((Plugin *)handle)->initialise(channels, stepSize, blockSize);
adapter->markOutputsChanged((Plugin *)handle);
return result ? 1 : 0;
}
void
PluginAdapterBase::Impl::vampReset(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampReset(" << handle << ")" << std::endl;
#endif
((Plugin *)handle)->reset();
}
float
PluginAdapterBase::Impl::vampGetParameter(VampPluginHandle handle,
int param)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetParameter(" << handle << ", " << param << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0.0;
Plugin::ParameterList &list = adapter->m_parameters;
return ((Plugin *)handle)->getParameter(list[param].identifier);
}
void
PluginAdapterBase::Impl::vampSetParameter(VampPluginHandle handle,
int param, float value)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampSetParameter(" << handle << ", " << param << ", " << value << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return;
Plugin::ParameterList &list = adapter->m_parameters;
((Plugin *)handle)->setParameter(list[param].identifier, value);
adapter->markOutputsChanged((Plugin *)handle);
}
unsigned int
PluginAdapterBase::Impl::vampGetCurrentProgram(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetCurrentProgram(" << handle << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0;
Plugin::ProgramList &list = adapter->m_programs;
std::string program = ((Plugin *)handle)->getCurrentProgram();
for (unsigned int i = 0; i < list.size(); ++i) {
if (list[i] == program) return i;
}
return 0;
}
void
PluginAdapterBase::Impl::vampSelectProgram(VampPluginHandle handle,
unsigned int program)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampSelectProgram(" << handle << ", " << program << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return;
Plugin::ProgramList &list = adapter->m_programs;
((Plugin *)handle)->selectProgram(list[program]);
adapter->markOutputsChanged((Plugin *)handle);
}
unsigned int
PluginAdapterBase::Impl::vampGetPreferredStepSize(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetPreferredStepSize(" << handle << ")" << std::endl;
#endif
return ((Plugin *)handle)->getPreferredStepSize();
}
unsigned int
PluginAdapterBase::Impl::vampGetPreferredBlockSize(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetPreferredBlockSize(" << handle << ")" << std::endl;
#endif
return ((Plugin *)handle)->getPreferredBlockSize();
}
unsigned int
PluginAdapterBase::Impl::vampGetMinChannelCount(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetMinChannelCount(" << handle << ")" << std::endl;
#endif
return ((Plugin *)handle)->getMinChannelCount();
}
unsigned int
PluginAdapterBase::Impl::vampGetMaxChannelCount(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetMaxChannelCount(" << handle << ")" << std::endl;
#endif
return ((Plugin *)handle)->getMaxChannelCount();
}
unsigned int
PluginAdapterBase::Impl::vampGetOutputCount(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetOutputCount(" << handle << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
// std::cerr << "vampGetOutputCount: handle " << handle << " -> adapter "<< adapter << std::endl;
if (!adapter) return 0;
return adapter->getOutputCount((Plugin *)handle);
}
VampOutputDescriptor *
PluginAdapterBase::Impl::vampGetOutputDescriptor(VampPluginHandle handle,
unsigned int i)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetOutputDescriptor(" << handle << ", " << i << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
// std::cerr << "vampGetOutputDescriptor: handle " << handle << " -> adapter "<< adapter << std::endl;
if (!adapter) return 0;
return adapter->getOutputDescriptor((Plugin *)handle, i);
}
void
PluginAdapterBase::Impl::vampReleaseOutputDescriptor(VampOutputDescriptor *desc)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampReleaseOutputDescriptor(" << desc << ")" << std::endl;
#endif
if (desc->identifier) free((void *)desc->identifier);
if (desc->name) free((void *)desc->name);
if (desc->description) free((void *)desc->description);
if (desc->unit) free((void *)desc->unit);
if (desc->hasFixedBinCount && desc->binNames) {
for (unsigned int i = 0; i < desc->binCount; ++i) {
if (desc->binNames[i]) {
free((void *)desc->binNames[i]);
}
}
}
if (desc->binNames) free((void *)desc->binNames);
free((void *)desc);
}
VampFeatureList *
PluginAdapterBase::Impl::vampProcess(VampPluginHandle handle,
const float *const *inputBuffers,
int sec,
int nsec)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampProcess(" << handle << ", " << sec << ", " << nsec << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0;
return adapter->process((Plugin *)handle, inputBuffers, sec, nsec);
}
VampFeatureList *
PluginAdapterBase::Impl::vampGetRemainingFeatures(VampPluginHandle handle)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampGetRemainingFeatures(" << handle << ")" << std::endl;
#endif
Impl *adapter = lookupAdapter(handle);
if (!adapter) return 0;
return adapter->getRemainingFeatures((Plugin *)handle);
}
void
PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList *)
{
#ifdef DEBUG_PLUGIN_ADAPTER
std::cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << std::endl;
#endif
}
void
PluginAdapterBase::Impl::cleanup(Plugin *plugin)
{
if (m_fs.find(plugin) != m_fs.end()) {
size_t outputCount = 0;
if (m_pluginOutputs[plugin]) {
outputCount = m_pluginOutputs[plugin]->size();
}
VampFeatureList *list = m_fs[plugin];
for (unsigned int i = 0; i < outputCount; ++i) {
for (unsigned int j = 0; j < m_fsizes[plugin][i]; ++j) {
if (list[i].features[j].v1.label) {
free(list[i].features[j].v1.label);
}
if (list[i].features[j].v1.values) {
free(list[i].features[j].v1.values);
}
}
if (list[i].features) free(list[i].features);
}
m_fs.erase(plugin);
m_fsizes.erase(plugin);
m_fvsizes.erase(plugin);
}
if (m_pluginOutputs.find(plugin) != m_pluginOutputs.end()) {
delete m_pluginOutputs[plugin];
m_pluginOutputs.erase(plugin);
}
if (m_adapterMap) {
m_adapterMap->erase(plugin);
if (m_adapterMap->empty()) {
delete m_adapterMap;
m_adapterMap = 0;
}
}
delete ((Plugin *)plugin);
}
void
PluginAdapterBase::Impl::checkOutputMap(Plugin *plugin)
{
OutputMap::iterator i = m_pluginOutputs.find(plugin);
if (i == m_pluginOutputs.end() || !i->second) {
m_pluginOutputs[plugin] = new Plugin::OutputList
(plugin->getOutputDescriptors());
// std::cerr << "PluginAdapterBase::Impl::checkOutputMap: Have " << m_pluginOutputs[plugin]->size() << " outputs for plugin " << plugin->getIdentifier() << std::endl;
}
}
void
PluginAdapterBase::Impl::markOutputsChanged(Plugin *plugin)
{
OutputMap::iterator i = m_pluginOutputs.find(plugin);
// std::cerr << "PluginAdapterBase::Impl::markOutputsChanged" << std::endl;
if (i != m_pluginOutputs.end()) {
Plugin::OutputList *list = i->second;
m_pluginOutputs.erase(i);
delete list;
}
}
unsigned int
PluginAdapterBase::Impl::getOutputCount(Plugin *plugin)
{
checkOutputMap(plugin);
return m_pluginOutputs[plugin]->size();
}
VampOutputDescriptor *
PluginAdapterBase::Impl::getOutputDescriptor(Plugin *plugin,
unsigned int i)
{
checkOutputMap(plugin);
Plugin::OutputDescriptor &od =
(*m_pluginOutputs[plugin])[i];
VampOutputDescriptor *desc = (VampOutputDescriptor *)
malloc(sizeof(VampOutputDescriptor));
desc->identifier = strdup(od.identifier.c_str());
desc->name = strdup(od.name.c_str());
desc->description = strdup(od.description.c_str());
desc->unit = strdup(od.unit.c_str());
desc->hasFixedBinCount = od.hasFixedBinCount;
desc->binCount = od.binCount;
if (od.hasFixedBinCount && od.binCount > 0
// We would like to do "&& !od.binNames.empty()" here -- but we
// can't, because it will crash older versions of the host adapter
// which try to copy the names across whenever the bin count is
// non-zero, regardless of whether they exist or not
) {
desc->binNames = (const char **)
malloc(od.binCount * sizeof(const char *));
for (unsigned int i = 0; i < od.binCount; ++i) {
if (i < od.binNames.size()) {
desc->binNames[i] = strdup(od.binNames[i].c_str());
} else {
desc->binNames[i] = 0;
}
}
} else {
desc->binNames = 0;
}
desc->hasKnownExtents = od.hasKnownExtents;
desc->minValue = od.minValue;
desc->maxValue = od.maxValue;
desc->isQuantized = od.isQuantized;
desc->quantizeStep = od.quantizeStep;
switch (od.sampleType) {
case Plugin::OutputDescriptor::OneSamplePerStep:
desc->sampleType = vampOneSamplePerStep; break;
case Plugin::OutputDescriptor::FixedSampleRate:
desc->sampleType = vampFixedSampleRate; break;
case Plugin::OutputDescriptor::VariableSampleRate:
desc->sampleType = vampVariableSampleRate; break;
}
desc->sampleRate = od.sampleRate;
desc->hasDuration = od.hasDuration;
return desc;
}
VampFeatureList *
PluginAdapterBase::Impl::process(Plugin *plugin,
const float *const *inputBuffers,
int sec, int nsec)
{
// std::cerr << "PluginAdapterBase::Impl::process" << std::endl;
RealTime rt(sec, nsec);
checkOutputMap(plugin);
return convertFeatures(plugin, plugin->process(inputBuffers, rt));
}
VampFeatureList *
PluginAdapterBase::Impl::getRemainingFeatures(Plugin *plugin)
{
// std::cerr << "PluginAdapterBase::Impl::getRemainingFeatures" << std::endl;
checkOutputMap(plugin);
return convertFeatures(plugin, plugin->getRemainingFeatures());
}
VampFeatureList *
PluginAdapterBase::Impl::convertFeatures(Plugin *plugin,
const Plugin::FeatureSet &features)
{
int lastN = -1;
int outputCount = 0;
if (m_pluginOutputs[plugin]) outputCount = m_pluginOutputs[plugin]->size();
resizeFS(plugin, outputCount);
VampFeatureList *fs = m_fs[plugin];
// std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: sizeof(Feature) == " << sizeof(Plugin::Feature) << ", sizeof(VampFeature) == " << sizeof(VampFeature) << ", sizeof(VampFeatureList) == " << sizeof(VampFeatureList) << std::endl;
for (Plugin::FeatureSet::const_iterator fi = features.begin();
fi != features.end(); ++fi) {
int n = fi->first;
// std::cerr << "PluginAdapterBase::Impl::convertFeatures: n = " << n << std::endl;
if (n >= int(outputCount)) {
std::cerr << "WARNING: PluginAdapterBase::Impl::convertFeatures: Too many outputs from plugin (" << n+1 << ", only should be " << outputCount << ")" << std::endl;
continue;
}
if (n > lastN + 1) {
for (int i = lastN + 1; i < n; ++i) {
fs[i].featureCount = 0;
}
}
const Plugin::FeatureList &fl = fi->second;
size_t sz = fl.size();
if (sz > m_fsizes[plugin][n]) resizeFL(plugin, n, sz);
fs[n].featureCount = sz;
for (size_t j = 0; j < sz; ++j) {
// std::cerr << "PluginAdapterBase::Impl::convertFeatures: j = " << j << std::endl;
VampFeature *feature = &fs[n].features[j].v1;
feature->hasTimestamp = fl[j].hasTimestamp;
feature->sec = fl[j].timestamp.sec;
feature->nsec = fl[j].timestamp.nsec;
feature->valueCount = fl[j].values.size();
VampFeatureV2 *v2 = &fs[n].features[j + sz].v2;
v2->hasDuration = fl[j].hasDuration;
v2->durationSec = fl[j].duration.sec;
v2->durationNsec = fl[j].duration.nsec;
if (feature->label) free(feature->label);
if (fl[j].label.empty()) {
feature->label = 0;
} else {
feature->label = strdup(fl[j].label.c_str());
}
if (feature->valueCount > m_fvsizes[plugin][n][j]) {
resizeFV(plugin, n, j, feature->valueCount);
}
for (unsigned int k = 0; k < feature->valueCount; ++k) {
// std::cerr << "PluginAdapterBase::Impl::convertFeatures: k = " << k << std::endl;
feature->values[k] = fl[j].values[k];
}
}
lastN = n;
}
if (lastN == -1) return 0;
if (int(outputCount) > lastN + 1) {
for (int i = lastN + 1; i < int(outputCount); ++i) {
fs[i].featureCount = 0;
}
}
// std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: have " << outputCount << " outputs" << std::endl;
// for (int i = 0; i < outputCount; ++i) {
// std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: output " << i << " has " << fs[i].featureCount << " features" << std::endl;
// }
return fs;
}
void
PluginAdapterBase::Impl::resizeFS(Plugin *plugin, int n)
{
// std::cerr << "PluginAdapterBase::Impl::resizeFS(" << plugin << ", " << n << ")" << std::endl;
int i = m_fsizes[plugin].size();
if (i >= n) return;
// std::cerr << "resizing from " << i << std::endl;
m_fs[plugin] = (VampFeatureList *)realloc
(m_fs[plugin], n * sizeof(VampFeatureList));
while (i < n) {
m_fs[plugin][i].featureCount = 0;
m_fs[plugin][i].features = 0;
m_fsizes[plugin].push_back(0);
m_fvsizes[plugin].push_back(std::vector<size_t>());
i++;
}
}
void
PluginAdapterBase::Impl::resizeFL(Plugin *plugin, int n, size_t sz)
{
// std::cerr << "PluginAdapterBase::Impl::resizeFL(" << plugin << ", " << n << ", "
// << sz << ")" << std::endl;
size_t i = m_fsizes[plugin][n];
if (i >= sz) return;
// std::cerr << "resizing from " << i << std::endl;
m_fs[plugin][n].features = (VampFeatureUnion *)realloc
(m_fs[plugin][n].features, 2 * sz * sizeof(VampFeatureUnion));
while (m_fsizes[plugin][n] < sz) {
m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.hasTimestamp = 0;
m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.valueCount = 0;
m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.values = 0;
m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.label = 0;
m_fs[plugin][n].features[m_fsizes[plugin][n] + sz].v2.hasDuration = 0;
m_fvsizes[plugin][n].push_back(0);
m_fsizes[plugin][n]++;
}
}
void
PluginAdapterBase::Impl::resizeFV(Plugin *plugin, int n, int j, size_t sz)
{
// std::cerr << "PluginAdapterBase::Impl::resizeFV(" << plugin << ", " << n << ", "
// << j << ", " << sz << ")" << std::endl;
size_t i = m_fvsizes[plugin][n][j];
if (i >= sz) return;
// std::cerr << "resizing from " << i << std::endl;
m_fs[plugin][n].features[j].v1.values = (float *)realloc
(m_fs[plugin][n].features[j].v1.values, sz * sizeof(float));
m_fvsizes[plugin][n][j] = sz;
}
PluginAdapterBase::Impl::AdapterMap *
PluginAdapterBase::Impl::m_adapterMap = 0;
}
_VAMP_SDK_PLUGSPACE_END(PluginAdapter.cpp)

View File

@@ -1,252 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
/*
This is a modified version of a source file from the
Rosegarden MIDI and audio sequencer and notation editor.
This file copyright 2000-2006 Chris Cannam.
Relicensed by the author as detailed above.
*/
#include <iostream>
#if (__GNUC__ < 3)
#include <strstream>
#define stringstream strstream
#else
#include <sstream>
#endif
using std::cerr;
using std::endl;
#ifndef _WIN32
#include <sys/time.h>
#endif
#include "vamp-sdk/RealTime.h"
_VAMP_SDK_PLUGSPACE_BEGIN(RealTime.cpp)
namespace Vamp {
// A RealTime consists of two ints that must be at least 32 bits each.
// A signed 32-bit int can store values exceeding +/- 2 billion. This
// means we can safely use our lower int for nanoseconds, as there are
// 1 billion nanoseconds in a second and we need to handle double that
// because of the implementations of addition etc that we use.
//
// The maximum valid RealTime on a 32-bit system is somewhere around
// 68 years: 999999999 nanoseconds longer than the classic Unix epoch.
#define ONE_BILLION 1000000000
RealTime::RealTime(int s, int n) :
sec(s), nsec(n)
{
if (sec == 0) {
while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
} else if (sec < 0) {
while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; }
while (nsec > 0) { nsec -= ONE_BILLION; ++sec; }
} else {
while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; }
while (nsec < 0) { nsec += ONE_BILLION; --sec; }
}
}
RealTime
RealTime::fromSeconds(double sec)
{
return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5));
}
RealTime
RealTime::fromMilliseconds(int msec)
{
return RealTime(msec / 1000, (msec % 1000) * 1000000);
}
#ifndef _WIN32
RealTime
RealTime::fromTimeval(const struct timeval &tv)
{
return RealTime(tv.tv_sec, tv.tv_usec * 1000);
}
#endif
std::ostream &operator<<(std::ostream &out, const RealTime &rt)
{
if (rt < RealTime::zeroTime) {
out << "-";
} else {
out << " ";
}
int s = (rt.sec < 0 ? -rt.sec : rt.sec);
int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec);
out << s << ".";
int nn(n);
if (nn == 0) out << "00000000";
else while (nn < (ONE_BILLION / 10)) {
out << "0";
nn *= 10;
}
out << n << "R";
return out;
}
std::string
RealTime::toString() const
{
std::stringstream out;
out << *this;
#if (__GNUC__ < 3)
out << std::ends;
#endif
std::string s = out.str();
// remove trailing R
return s.substr(0, s.length() - 1);
}
std::string
RealTime::toText(bool fixedDp) const
{
if (*this < RealTime::zeroTime) return "-" + (-*this).toText();
std::stringstream out;
if (sec >= 3600) {
out << (sec / 3600) << ":";
}
if (sec >= 60) {
out << (sec % 3600) / 60 << ":";
}
if (sec >= 10) {
out << ((sec % 60) / 10);
}
out << (sec % 10);
int ms = msec();
if (ms != 0) {
out << ".";
out << (ms / 100);
ms = ms % 100;
if (ms != 0) {
out << (ms / 10);
ms = ms % 10;
} else if (fixedDp) {
out << "0";
}
if (ms != 0) {
out << ms;
} else if (fixedDp) {
out << "0";
}
} else if (fixedDp) {
out << ".000";
}
#if (__GNUC__ < 3)
out << std::ends;
#endif
std::string s = out.str();
return s;
}
RealTime
RealTime::operator/(int d) const
{
int secdiv = sec / d;
int secrem = sec % d;
double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d;
return RealTime(secdiv, int(nsecdiv + 0.5));
}
double
RealTime::operator/(const RealTime &r) const
{
double lTotal = double(sec) * ONE_BILLION + double(nsec);
double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec);
if (rTotal == 0) return 0.0;
else return lTotal/rTotal;
}
long
RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate)
{
if (time < zeroTime) return -realTime2Frame(-time, sampleRate);
double s = time.sec + double(time.nsec + 1) / 1000000000.0;
return long(s * sampleRate);
}
RealTime
RealTime::frame2RealTime(long frame, unsigned int sampleRate)
{
if (frame < 0) return -frame2RealTime(-frame, sampleRate);
RealTime rt;
rt.sec = frame / long(sampleRate);
frame -= rt.sec * long(sampleRate);
rt.nsec = (int)(((double(frame) * 1000000.0) / sampleRate) * 1000.0);
return rt;
}
const RealTime RealTime::zeroTime(0,0);
}
_VAMP_SDK_PLUGSPACE_END(RealTime.cpp)

View File

@@ -1,47 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_HOSTSDK_PLUGIN_H_
#define _VAMP_HOSTSDK_PLUGIN_H_
// Do not include vamp-sdk/Plugin.h directly from host code. Always
// use this header instead.
#include "hostguard.h"
#include "vamp-sdk/Plugin.h"
#endif

View File

@@ -1,47 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_HOSTSDK_PLUGIN_BASE_H_
#define _VAMP_HOSTSDK_PLUGIN_BASE_H_
// Do not include vamp-sdk/PluginBase.h directly from host code.
// Always use this header instead.
#include "hostguard.h"
#include "vamp-sdk/PluginBase.h"
#endif

View File

@@ -1,194 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2009 Chris Cannam and QMUL.
This file by Mark Levy and Chris Cannam, Copyright 2007-2008 QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_PLUGIN_BUFFERING_ADAPTER_H_
#define _VAMP_PLUGIN_BUFFERING_ADAPTER_H_
#include "hostguard.h"
#include "PluginWrapper.h"
_VAMP_SDK_HOSTSPACE_BEGIN(PluginBufferingAdapter.h)
namespace Vamp {
namespace HostExt {
/**
* \class PluginBufferingAdapter PluginBufferingAdapter.h <vamp-hostsdk/PluginBufferingAdapter.h>
*
* PluginBufferingAdapter is a Vamp plugin adapter that allows plugins
* to be used by a host supplying an audio stream in non-overlapping
* buffers of arbitrary size.
*
* A host using PluginBufferingAdapter may ignore the preferred step
* and block size reported by the plugin, and still expect the plugin
* to run. The value of blockSize and stepSize passed to initialise
* should be the size of the buffer which the host will supply; the
* stepSize should be equal to the blockSize.
*
* If the internal step size used for the plugin differs from that
* supplied by the host, the adapter will modify the sample type and
* rate specifications for the plugin outputs appropriately, and set
* timestamps on the output features for outputs that formerly used a
* different sample rate specification. This is necessary in order to
* obtain correct time stamping.
*
* In other respects, the PluginBufferingAdapter behaves identically
* to the plugin that it wraps. The wrapped plugin will be deleted
* when the wrapper is deleted.
*/
class PluginBufferingAdapter : public PluginWrapper
{
public:
/**
* Construct a PluginBufferingAdapter wrapping the given plugin.
* The adapter takes ownership of the plugin, which will be
* deleted when the adapter is deleted.
*/
PluginBufferingAdapter(Plugin *plugin);
virtual ~PluginBufferingAdapter();
/**
* Return the preferred step size for this adapter.
*
* Because of the way this adapter works, its preferred step size
* will always be the same as its preferred block size. This may
* or may not be the same as the preferred step size of the
* underlying plugin, which may be obtained by calling
* getPluginPreferredStepSize().
*/
size_t getPreferredStepSize() const;
/**
* Return the preferred block size for this adapter.
*
* This may or may not be the same as the preferred block size of
* the underlying plugin, which may be obtained by calling
* getPluginPreferredBlockSize().
*
* Note that this adapter may be initialised with any block size,
* not just its supposedly preferred one.
*/
size_t getPreferredBlockSize() const;
/**
* Initialise the adapter (and therefore the plugin) for the given
* number of channels. Initialise the adapter for the given step
* and block size, which must be equal.
*
* The step and block size used for the underlying plugin will
* depend on its preferences, or any values previously passed to
* setPluginStepSize and setPluginBlockSize.
*/
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
/**
* Return the preferred step size of the plugin wrapped by this
* adapter.
*
* This is included mainly for informational purposes. This value
* is not likely to be a valid step size for the adapter itself,
* and it is not usually of any use in interpreting the results
* (because the adapter re-writes OneSamplePerStep outputs to
* FixedSampleRate so that the hop size no longer needs to be
* known beforehand in order to interpret them).
*/
size_t getPluginPreferredStepSize() const;
/**
* Return the preferred block size of the plugin wrapped by this
* adapter.
*
* This is included mainly for informational purposes.
*/
size_t getPluginPreferredBlockSize() const;
/**
* Set the step size that will be used for the underlying plugin
* when initialise() is called. If this is not set, the plugin's
* own preferred step size will be used. You will not usually
* need to call this function. If you do call it, it must be
* before the first call to initialise().
*/
void setPluginStepSize(size_t stepSize);
/**
* Set the block size that will be used for the underlying plugin
* when initialise() is called. If this is not set, the plugin's
* own preferred block size will be used. You will not usually
* need to call this function. If you do call it, it must be
* before the first call to initialise().
*/
void setPluginBlockSize(size_t blockSize);
/**
* Return the step and block sizes that were actually used when
* initialising the underlying plugin.
*
* This is included mainly for informational purposes. You will
* not usually need to call this function. If this is called
* before initialise(), it will return 0 for both values. If it
* is called after a failed call to initialise(), it will return
* the values that were used in the failed call to the plugin's
* initialise() function.
*/
void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
void setParameter(std::string, float);
void selectProgram(std::string);
OutputList getOutputDescriptors() const;
void reset();
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures();
protected:
class Impl;
Impl *m_impl;
};
}
}
_VAMP_SDK_HOSTSPACE_END(PluginBufferingAdapter.h)
#endif

View File

@@ -1,149 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_PLUGIN_CHANNEL_ADAPTER_H_
#define _VAMP_PLUGIN_CHANNEL_ADAPTER_H_
#include "hostguard.h"
#include "PluginWrapper.h"
_VAMP_SDK_HOSTSPACE_BEGIN(PluginChannelAdapter.h)
namespace Vamp {
namespace HostExt {
/**
* \class PluginChannelAdapter PluginChannelAdapter.h <vamp-hostsdk/PluginChannelAdapter.h>
*
* PluginChannelAdapter is a Vamp plugin adapter that implements a
* policy for management of plugins that expect a different number of
* input channels from the number actually available in the source
* audio data.
*
* A host using PluginChannelAdapter may ignore the getMinChannelCount
* and getMaxChannelCount reported by the plugin, and still expect the
* plugin to run.
*
* PluginChannelAdapter implements the following policy:
*
* - If the plugin supports the provided number of channels directly,
* PluginChannelAdapter will just run the plugin as normal.
*
* - If the plugin only supports exactly one channel but more than
* one channel is provided, PluginChannelAdapter will use the mean of
* the channels. This ensures that the resulting values remain
* within the same magnitude range as expected for mono data.
*
* - If the plugin requires more than one channel but exactly one is
* provided, the provided channel will be duplicated across all the
* plugin input channels.
*
* If none of the above apply:
*
* - If the plugin requires more channels than are provided, the
* minimum acceptable number of channels will be produced by adding
* empty (zero valued) channels to those provided.
*
* - If the plugin requires fewer channels than are provided, the
* maximum acceptable number of channels will be produced by
* discarding the excess channels.
*
* Hosts requiring a different channel policy from the above will need
* to implement it themselves, instead of using PluginChannelAdapter.
*
* Note that PluginChannelAdapter does not override the minimum and
* maximum channel counts returned by the wrapped plugin. The host
* will need to be aware that it is using a PluginChannelAdapter, and
* be prepared to ignore these counts as necessary. (This contrasts
* with the approach used in PluginInputDomainAdapter, which aims to
* make the host completely unaware of which underlying input domain
* is in fact in use.)
*
* (The rationale for this is that a host may wish to use the
* PluginChannelAdapter but still discriminate in some way on the
* basis of the number of channels actually supported. For example, a
* simple stereo audio host may prefer to reject plugins that require
* more than two channels on the grounds that doesn't actually
* understand what they are for, rather than allow the channel adapter
* to make a potentially meaningless channel conversion for them.)
*
* In every respect other than its management of channels, the
* PluginChannelAdapter behaves identically to the plugin that it
* wraps. The wrapped plugin will be deleted when the wrapper is
* deleted.
*
* \note This class was introduced in version 1.1 of the Vamp plugin SDK.
*/
class PluginChannelAdapter : public PluginWrapper
{
public:
/**
* Construct a PluginChannelAdapter wrapping the given plugin.
* The adapter takes ownership of the plugin, which will be
* deleted when the adapter is deleted.
*/
PluginChannelAdapter(Plugin *plugin);
virtual ~PluginChannelAdapter();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
/**
* Call process(), providing interleaved audio data with the
* number of channels passed to initialise(). The adapter will
* de-interleave into temporary buffers as appropriate before
* calling process().
*
* \note This function was introduced in version 1.4 of the Vamp
* plugin SDK.
*/
FeatureSet processInterleaved(const float *inputBuffer, RealTime timestamp);
protected:
class Impl;
Impl *m_impl;
};
}
}
_VAMP_SDK_HOSTSPACE_END(PluginChannelAdapter.h)
#endif

View File

@@ -1,123 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_PLUGIN_HOST_ADAPTER_H_
#define _VAMP_PLUGIN_HOST_ADAPTER_H_
#include "hostguard.h"
#include "Plugin.h"
#include "vamp/vamp.h"
#include <vector>
_VAMP_SDK_HOSTSPACE_BEGIN(PluginHostAdapter.h)
namespace Vamp {
/**
* \class PluginHostAdapter PluginHostAdapter.h <vamp-hostsdk/PluginHostAdapter.h>
*
* PluginHostAdapter is a wrapper class that a Vamp host can use to
* make the C-language VampPluginDescriptor object appear as a C++
* Vamp::Plugin object.
*
* The Vamp API is defined in vamp/vamp.h as a C API. The C++ objects
* used for convenience by plugins and hosts actually communicate
* using the C low-level API, but the details of this communication
* are handled seamlessly by the Vamp SDK implementation provided the
* plugin and host use the proper C++ wrapper objects.
*
* See also PluginAdapter, the plugin-side wrapper that makes a C++
* plugin object available using the C query API.
*/
class PluginHostAdapter : public Plugin
{
public:
PluginHostAdapter(const VampPluginDescriptor *descriptor,
float inputSampleRate);
virtual ~PluginHostAdapter();
static std::vector<std::string> getPluginPath();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
InputDomain getInputDomain() const;
unsigned int getVampApiVersion() const;
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) const;
void setParameter(std::string, float);
ProgramList getPrograms() const;
std::string getCurrentProgram() const;
void selectProgram(std::string);
size_t getPreferredStepSize() const;
size_t getPreferredBlockSize() const;
size_t getMinChannelCount() const;
size_t getMaxChannelCount() const;
OutputList getOutputDescriptors() const;
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures();
protected:
void convertFeatures(VampFeatureList *, FeatureSet &);
const VampPluginDescriptor *m_descriptor;
VampPluginHandle m_handle;
};
}
_VAMP_SDK_HOSTSPACE_END(PluginHostAdapter.h)
#endif

View File

@@ -1,198 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_PLUGIN_INPUT_DOMAIN_ADAPTER_H_
#define _VAMP_PLUGIN_INPUT_DOMAIN_ADAPTER_H_
#include "hostguard.h"
#include "PluginWrapper.h"
_VAMP_SDK_HOSTSPACE_BEGIN(PluginInputDomainAdapter.h)
namespace Vamp {
namespace HostExt {
/**
* \class PluginInputDomainAdapter PluginInputDomainAdapter.h <vamp-hostsdk/PluginInputDomainAdapter.h>
*
* PluginInputDomainAdapter is a Vamp plugin adapter that converts
* time-domain input into frequency-domain input for plugins that need
* it. This permits a host to use time- and frequency-domain plugins
* interchangeably without needing to handle the conversion itself.
*
* This adapter uses a basic Hanning windowed FFT that supports
* power-of-two block sizes only. If a frequency domain plugin
* requests a non-power-of-two blocksize, the adapter will adjust it
* to a nearby power of two instead. Thus, getPreferredBlockSize()
* will always return a power of two if the wrapped plugin is a
* frequency domain one. If the plugin doesn't accept the adjusted
* power of two block size, initialise() will fail.
*
* The adapter provides no way for the host to discover whether the
* underlying plugin is actually a time or frequency domain plugin
* (except that if the preferred block size is not a power of two, it
* must be a time domain plugin).
*
* The FFT implementation is simple and self-contained, but unlikely
* to be the fastest available: a host can usually do better if it
* cares enough.
*
* In every respect other than its input domain handling, the
* PluginInputDomainAdapter behaves identically to the plugin that it
* wraps. The wrapped plugin will be deleted when the wrapper is
* deleted.
*
* \note This class was introduced in version 1.1 of the Vamp plugin SDK.
*/
class PluginInputDomainAdapter : public PluginWrapper
{
public:
/**
* Construct a PluginInputDomainAdapter wrapping the given plugin.
* The adapter takes ownership of the plugin, which will be
* deleted when the adapter is deleted.
*/
PluginInputDomainAdapter(Plugin *plugin);
virtual ~PluginInputDomainAdapter();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
InputDomain getInputDomain() const;
size_t getPreferredStepSize() const;
size_t getPreferredBlockSize() const;
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
/**
* ProcessTimestampMethod determines how the
* PluginInputDomainAdapter handles timestamps for the data passed
* to the process() function of the plugin it wraps, in the case
* where the plugin is expecting frequency-domain data.
*
* The Vamp specification requires that the timestamp passed to
* the plugin for frequency-domain input should be that of the
* centre of the processing block, rather than the start as is the
* case for time-domain input.
*
* Since PluginInputDomainAdapter aims to be transparent in use,
* it needs to handle this timestamp adjustment itself. However,
* some control is available over the method used for adjustment,
* by means of the ProcessTimestampMethod setting.
*
* If ProcessTimestampMethod is set to ShiftTimestamp (the
* default), then the data passed to the wrapped plugin will be
* calculated from the same input data block as passed to the
* wrapper, but the timestamp passed to the plugin will be
* advanced by half of the window size.
*
* If ProcessTimestampMethod is set to ShiftData, then the
* timestamp passed to the wrapped plugin will be the same as that
* passed to the process call of the wrapper, but the data block
* used to calculate the input will be shifted back (earlier) by
* half of the window size, with half a block of zero padding at
* the start of the first process call. This has the advantage of
* preserving the first half block of audio without any
* deterioration from window shaping.
*
* If ProcessTimestampMethod is set to NoShift, then no adjustment
* will be made and the timestamps will be incorrect.
*/
enum ProcessTimestampMethod {
ShiftTimestamp,
ShiftData,
NoShift
};
/**
* Set the method used for timestamp adjustment in plugins taking
* frequency-domain input. See the ProcessTimestampMethod
* documentation for details.
*
* This function must be called before the first call to
* process().
*/
void setProcessTimestampMethod(ProcessTimestampMethod);
/**
* Retrieve the method used for timestamp adjustment in plugins
* taking frequency-domain input. See the ProcessTimestampMethod
* documentation for details.
*/
ProcessTimestampMethod getProcessTimestampMethod() const;
/**
* Return the amount by which the timestamps supplied to process()
* are being incremented when they are passed to the plugin's own
* process() implementation.
*
* The Vamp API mandates that the timestamp passed to the plugin
* for time-domain input should be the time of the first sample in
* the block, but the timestamp passed for frequency-domain input
* should be the timestamp of the centre of the block.
*
* The PluginInputDomainAdapter adjusts its timestamps properly so
* that the plugin receives correct times, but in some
* circumstances (such as for establishing the correct timing of
* implicitly-timed features, i.e. features without their own
* timestamps) the host may need to be aware that this adjustment
* is taking place.
*
* If the plugin requires time-domain input or the
* PluginInputDomainAdapter is configured with its
* ProcessTimestampMethod set to ShiftData instead of
* ShiftTimestamp, then this function will return zero.
*
* The result of calling this function before initialise() has
* been called is undefined.
*/
RealTime getTimestampAdjustment() const;
protected:
class Impl;
Impl *m_impl;
};
}
}
_VAMP_SDK_HOSTSPACE_END(PluginInputDomainAdapter.h)
#endif

View File

@@ -1,243 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_PLUGIN_LOADER_H_
#define _VAMP_PLUGIN_LOADER_H_
#include <vector>
#include <string>
#include <map>
#include "hostguard.h"
#include "PluginWrapper.h"
_VAMP_SDK_HOSTSPACE_BEGIN(PluginLoader.h)
namespace Vamp {
class Plugin;
namespace HostExt {
/**
* \class PluginLoader PluginLoader.h <vamp-hostsdk/PluginLoader.h>
*
* Vamp::HostExt::PluginLoader is a convenience class for discovering
* and loading Vamp plugins using the typical plugin-path, library
* naming, and categorisation conventions described in the Vamp SDK
* documentation. This class is intended to greatly simplify the task
* of becoming a Vamp plugin host for any C++ application.
*
* Hosts are not required by the Vamp specification to use the same
* plugin search path and naming conventions as implemented by this
* class, and are certainly not required to use this actual class.
* But we do strongly recommend it.
*
* \note This class was introduced in version 1.1 of the Vamp plugin SDK.
*/
class PluginLoader
{
public:
/**
* Obtain a pointer to the singleton instance of PluginLoader.
* Use this to obtain your loader object.
*/
static PluginLoader *getInstance();
/**
* PluginKey is a string type that is used to identify a plugin
* uniquely within the scope of "the current system". It consists
* of the lower-cased base name of the plugin library, a colon
* separator, and the identifier string for the plugin. It is
* only meaningful in the context of a given plugin path (the one
* returned by PluginHostAdapter::getPluginPath()).
*
* Use composePluginKey() to construct a plugin key from a known
* plugin library name and identifier.
*
* Note: the fact that the library component of the key is
* lower-cased implies that library names are matched
* case-insensitively by the PluginLoader class, regardless of the
* case sensitivity of the underlying filesystem. (Plugin
* identifiers _are_ case sensitive, however.) Also, it is not
* possible to portably extract a working library name from a
* plugin key, as the result may fail on case-sensitive
* filesystems. Use getLibraryPathForPlugin() instead.
*/
typedef std::string PluginKey;
/**
* PluginKeyList is a sequence of plugin keys, such as returned by
* listPlugins().
*/
typedef std::vector<PluginKey> PluginKeyList;
/**
* PluginCategoryHierarchy is a sequence of general->specific
* category names, as may be associated with a single plugin.
* This sequence describes the location of a plugin within a
* category forest, containing the human-readable names of the
* plugin's category tree root, followed by each of the nodes down
* to the leaf containing the plugin.
*
* \see getPluginCategory()
*/
typedef std::vector<std::string> PluginCategoryHierarchy;
/**
* Search for all available Vamp plugins, and return a list of
* them in the order in which they were found.
*/
PluginKeyList listPlugins();
/**
* AdapterFlags contains a set of values that may be OR'd together
* to indicate in which circumstances PluginLoader should use a
* plugin adapter to make a plugin easier to use for a host that
* does not want to cater for complex features.
*
* The available flags are:
*
* ADAPT_INPUT_DOMAIN - If the plugin expects frequency domain
* input, wrap it in a PluginInputDomainAdapter that automatically
* converts the plugin to one that expects time-domain input.
* This enables a host to accommodate time- and frequency-domain
* plugins without needing to do any conversion itself.
*
* ADAPT_CHANNEL_COUNT - Wrap the plugin in a PluginChannelAdapter
* to handle any mismatch between the number of channels of audio
* the plugin can handle and the number available in the host.
* This enables a host to use plugins that may require the input
* to be mixed down to mono, etc., without having to worry about
* doing that itself.
*
* ADAPT_BUFFER_SIZE - Wrap the plugin in a PluginBufferingAdapter
* permitting the host to provide audio input using any block
* size, with no overlap, regardless of the plugin's preferred
* block size (suitable for hosts that read from non-seekable
* streaming media, for example). This adapter introduces some
* run-time overhead and also changes the semantics of the plugin
* slightly (see the PluginBufferingAdapter header documentation
* for details).
*
* ADAPT_ALL_SAFE - Perform all available adaptations that are
* meaningful for the plugin and "safe". Currently this means to
* ADAPT_INPUT_DOMAIN if the plugin wants FrequencyDomain input;
* ADAPT_CHANNEL_COUNT always; and ADAPT_BUFFER_SIZE never.
*
* ADAPT_ALL - Perform all available adaptations that are
* meaningful for the plugin.
*
* See PluginInputDomainAdapter, PluginChannelAdapter and
* PluginBufferingAdapter for more details of the classes that the
* loader may use if these flags are set.
*/
enum AdapterFlags {
ADAPT_INPUT_DOMAIN = 0x01,
ADAPT_CHANNEL_COUNT = 0x02,
ADAPT_BUFFER_SIZE = 0x04,
ADAPT_ALL_SAFE = 0x03,
ADAPT_ALL = 0xff
};
/**
* Load a Vamp plugin, given its identifying key. If the plugin
* could not be loaded, returns 0.
*
* The returned plugin should be deleted (using the standard C++
* delete keyword) after use.
*
* \param adapterFlags a bitwise OR of the values in the AdapterFlags
* enumeration, indicating under which circumstances an adapter should be
* used to wrap the original plugin. If adapterFlags is 0, no
* optional adapters will be used. Otherwise, the returned plugin
* may be of an adapter class type which will behave identically
* to the original plugin, apart from any particular features
* implemented by the adapter itself.
*
* \see AdapterFlags, PluginInputDomainAdapter, PluginChannelAdapter
*/
Plugin *loadPlugin(PluginKey key,
float inputSampleRate,
int adapterFlags = 0);
/**
* Given a Vamp plugin library name and plugin identifier, return
* the corresponding plugin key in a form suitable for passing in to
* loadPlugin().
*/
PluginKey composePluginKey(std::string libraryName,
std::string identifier);
/**
* Return the category hierarchy for a Vamp plugin, given its
* identifying key.
*
* If the plugin has no category information, return an empty
* hierarchy.
*
* \see PluginCategoryHierarchy
*/
PluginCategoryHierarchy getPluginCategory(PluginKey plugin);
/**
* Return the file path of the dynamic library from which the
* given plugin will be loaded (if available).
*/
std::string getLibraryPathForPlugin(PluginKey plugin);
protected:
PluginLoader();
virtual ~PluginLoader();
class Impl;
Impl *m_impl;
static PluginLoader *m_instance;
};
}
}
_VAMP_SDK_HOSTSPACE_END(PluginLoader.h)
#endif

View File

@@ -1,197 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_PLUGIN_SUMMARISING_ADAPTER_H_
#define _VAMP_PLUGIN_SUMMARISING_ADAPTER_H_
#include "hostguard.h"
#include "PluginWrapper.h"
#include <set>
_VAMP_SDK_HOSTSPACE_BEGIN(PluginSummarisingAdapter.h)
namespace Vamp {
namespace HostExt {
/**
* \class PluginSummarisingAdapter PluginSummarisingAdapter.h <vamp-hostsdk/PluginSummarisingAdapter.h>
*
* PluginSummarisingAdapter is a Vamp plugin adapter that provides
* summarisation methods such as mean and median averages of output
* features, for use in any context where an available plugin produces
* individual values but the result that is actually needed is some
* sort of aggregate.
*
* To make use of PluginSummarisingAdapter, the host should configure,
* initialise and run the plugin through the adapter interface just as
* normal. Then, after the process and getRemainingFeatures methods
* have been properly called and processing is complete, the host may
* call getSummaryForOutput or getSummaryForAllOutputs to obtain
* summarised features: averages, maximum values, etc, depending on
* the SummaryType passed to the function.
*
* By default PluginSummarisingAdapter calculates a single summary of
* each output's feature across the whole duration of processed audio.
* A host needing summaries of sub-segments of the whole audio may
* call setSummarySegmentBoundaries before retrieving the summaries,
* providing a list of times such that one summary will be provided
* for each segment between two consecutive times.
*
* PluginSummarisingAdapter is straightforward rather than fast. It
* calculates all of the summary types for all outputs always, and
* then returns only the ones that are requested. It is designed on
* the basis that, for most features, summarising and storing
* summarised results is far cheaper than calculating the results in
* the first place. If this is not true for your particular feature,
* PluginSummarisingAdapter may not be the best approach for you.
*
* \note This class was introduced in version 2.0 of the Vamp plugin SDK.
*/
class PluginSummarisingAdapter : public PluginWrapper
{
public:
/**
* Construct a PluginSummarisingAdapter wrapping the given plugin.
* The adapter takes ownership of the plugin, which will be
* deleted when the adapter is deleted.
*/
PluginSummarisingAdapter(Plugin *plugin);
virtual ~PluginSummarisingAdapter();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures();
typedef std::set<RealTime> SegmentBoundaries;
/**
* Specify a series of segment boundaries, such that one summary
* will be returned for each of the contiguous intra-boundary
* segments. This function must be called before
* getSummaryForOutput or getSummaryForAllOutputs.
*
* Note that you cannot retrieve results with multiple different
* segmentations by repeatedly calling this function followed by
* one of the getSummary functions. The summaries are all
* calculated at the first call to any getSummary function, and
* once the summaries have been calculated, they remain
* calculated.
*/
void setSummarySegmentBoundaries(const SegmentBoundaries &);
enum SummaryType {
Minimum = 0,
Maximum = 1,
Mean = 2,
Median = 3,
Mode = 4,
Sum = 5,
Variance = 6,
StandardDeviation = 7,
Count = 8,
UnknownSummaryType = 999
};
/**
* AveragingMethod indicates how the adapter should handle
* average-based summaries of features whose results are not
* equally spaced in time.
*
* If SampleAverage is specified, summary types based on averages
* will be calculated by treating each result individually without
* regard to its time: for example, the mean will be the sum of
* all values divided by the number of values.
*
* If ContinuousTimeAverage is specified, each feature will be
* considered to have a duration, either as specified in the
* feature's duration field, or until the following feature: thus,
* for example, the mean will be the sum of the products of values
* and durations, divided by the total duration.
*
* Although SampleAverage is useful for many types of feature,
* ContinuousTimeAverage is essential for some situations, for
* example finding the result that spans the largest proportion of
* the input given a feature that emits a new result only when the
* value changes (the modal value integrated over time).
*/
enum AveragingMethod {
SampleAverage = 0,
ContinuousTimeAverage = 1
};
/**
* Return summaries of the features that were returned on the
* given output, using the given SummaryType and AveragingMethod.
*
* The plugin must have been fully run (process() and
* getRemainingFeatures() calls all made as appropriate) before
* this function is called.
*/
FeatureList getSummaryForOutput(int output,
SummaryType type,
AveragingMethod method = SampleAverage);
/**
* Return summaries of the features that were returned on all of
* the plugin's outputs, using the given SummaryType and
* AveragingMethod.
*
* The plugin must have been fully run (process() and
* getRemainingFeatures() calls all made as appropriate) before
* this function is called.
*/
FeatureSet getSummaryForAllOutputs(SummaryType type,
AveragingMethod method = SampleAverage);
protected:
class Impl;
Impl *m_impl;
};
}
}
_VAMP_SDK_HOSTSPACE_END(PluginSummarisingAdapter.h)
#endif

View File

@@ -1,135 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006-2009 Chris Cannam and QMUL.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_PLUGIN_WRAPPER_H_
#define _VAMP_PLUGIN_WRAPPER_H_
#include "hostguard.h"
#include "vamp-hostsdk/Plugin.h"
_VAMP_SDK_HOSTSPACE_BEGIN(PluginWrapper.h)
namespace Vamp {
namespace HostExt {
/**
* \class PluginWrapper PluginWrapper.h <vamp-hostsdk/PluginWrapper.h>
*
* PluginWrapper is a simple base class for adapter plugins. It takes
* a pointer to a "to be wrapped" Vamp plugin on construction, and
* provides implementations of all the Vamp plugin methods that simply
* delegate through to the wrapped plugin. A subclass can therefore
* override only the methods that are meaningful for the particular
* adapter.
*
* \note This class was introduced in version 1.1 of the Vamp plugin SDK.
*/
class PluginWrapper : public Plugin
{
public:
virtual ~PluginWrapper();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
void reset();
InputDomain getInputDomain() const;
unsigned int getVampApiVersion() const;
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) const;
void setParameter(std::string, float);
ProgramList getPrograms() const;
std::string getCurrentProgram() const;
void selectProgram(std::string);
size_t getPreferredStepSize() const;
size_t getPreferredBlockSize() const;
size_t getMinChannelCount() const;
size_t getMaxChannelCount() const;
OutputList getOutputDescriptors() const;
FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
FeatureSet getRemainingFeatures();
/**
* Return a pointer to the plugin wrapper of type WrapperType
* surrounding this wrapper's plugin, if present.
*
* This is useful in situations where a plugin is wrapped by
* multiple different wrappers (one inside another) and the host
* wants to call some wrapper-specific function on one of the
* layers without having to care about the order in which they are
* wrapped. For example, the plugin returned by
* PluginLoader::loadPlugin may have more than one wrapper; if the
* host wanted to query or fine-tune some property of one of them,
* it would be hard to do so without knowing the order of the
* wrappers. This function therefore gives direct access to the
* wrapper of a particular type.
*/
template <typename WrapperType>
WrapperType *getWrapper() {
WrapperType *w = dynamic_cast<WrapperType *>(this);
if (w) return w;
PluginWrapper *pw = dynamic_cast<PluginWrapper *>(m_plugin);
if (pw) return pw->getWrapper<WrapperType>();
return 0;
}
protected:
PluginWrapper(Plugin *plugin); // I take ownership of plugin
Plugin *m_plugin;
};
}
}
_VAMP_SDK_HOSTSPACE_END(PluginWrapper.h)
#endif

View File

@@ -1,46 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_HOSTSDK_REALTIME_H_
#define _VAMP_HOSTSDK_REALTIME_H_
// Do not include vamp-sdk/RealTime.h directly from host code. Always
// use this header instead.
#include "hostguard.h"
#include "vamp-sdk/RealTime.h"
#endif

View File

@@ -1,69 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_HOSTSDK_HOSTGUARD_H_
#define _VAMP_HOSTSDK_HOSTGUARD_H_
#ifdef _VAMP_IN_PLUGINSDK
#error You have included headers from both vamp-sdk and vamp-hostsdk in the same source file. Please include only vamp-sdk headers in plugin code, and only vamp-hostsdk headers in host code.
#else
#define _VAMP_IN_HOSTSDK
#ifdef _VAMP_NO_HOST_NAMESPACE
#define _VAMP_SDK_HOSTSPACE_BEGIN(h)
#define _VAMP_SDK_HOSTSPACE_END(h)
#define _VAMP_SDK_PLUGSPACE_BEGIN(h)
#define _VAMP_SDK_PLUGSPACE_END(h)
#else
#define _VAMP_SDK_HOSTSPACE_BEGIN(h) \
namespace _VampHost {
#define _VAMP_SDK_HOSTSPACE_END(h) \
} \
using namespace _VampHost;
#define _VAMP_SDK_PLUGSPACE_BEGIN(h) \
namespace _VampHost {
#define _VAMP_SDK_PLUGSPACE_END(h) \
} \
using namespace _VampHost;
#endif
#endif
#endif

View File

@@ -1,53 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_HOSTSDK_SINGLE_INCLUDE_H_
#define _VAMP_HOSTSDK_SINGLE_INCLUDE_H_
#include "PluginBase.h"
#include "PluginBufferingAdapter.h"
#include "PluginChannelAdapter.h"
#include "Plugin.h"
#include "PluginHostAdapter.h"
#include "PluginInputDomainAdapter.h"
#include "PluginLoader.h"
#include "PluginSummarisingAdapter.h"
#include "PluginWrapper.h"
#include "RealTime.h"
#endif

View File

@@ -1,446 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_SDK_PLUGIN_H_
#define _VAMP_SDK_PLUGIN_H_
#include <string>
#include <vector>
#include <map>
#include "PluginBase.h"
#include "RealTime.h"
#include "plugguard.h"
_VAMP_SDK_PLUGSPACE_BEGIN(Plugin.h)
namespace Vamp {
/**
* \class Plugin Plugin.h <vamp-sdk/Plugin.h>
*
* Vamp::Plugin is a base class for plugin instance classes
* that provide feature extraction from audio or related data.
*
* In most cases, the input will be audio and the output will be a
* stream of derived data at a lower sampling resolution than the
* input.
*
* Note that this class inherits several abstract methods from
* PluginBase. These must be implemented by the subclass.
*
*
* PLUGIN LIFECYCLE
*
* Feature extraction plugins are managed differently from real-time
* plugins (such as VST effects). The main difference is that the
* parameters for a feature extraction plugin are configured before
* the plugin is used, and do not change during use.
*
* 1. Host constructs the plugin, passing it the input sample rate.
* The plugin may do basic initialisation, but should not do anything
* computationally expensive at this point. You must make sure your
* plugin is cheap to construct, otherwise you'll seriously affect the
* startup performance of almost all hosts. If you have serious
* initialisation to do, the proper place is in initialise() (step 5).
*
* 2. Host may query the plugin's available outputs.
*
* 3. Host queries programs and parameter descriptors, and may set
* some or all of them. Parameters that are not explicitly set should
* take their default values as specified in the parameter descriptor.
* When a program is set, the parameter values may change and the host
* will re-query them to check.
*
* 4. Host queries the preferred step size, block size and number of
* channels. These may all vary depending on the parameter values.
* (Note however that you cannot make the number of distinct outputs
* dependent on parameter values.)
*
* 5. Plugin is properly initialised with a call to initialise. This
* fixes the step size, block size, and number of channels, as well as
* all of the parameter and program settings. If the values passed in
* to initialise do not match the plugin's advertised preferred values
* from step 4, the plugin may refuse to initialise and return false
* (although if possible it should accept the new values). Any
* computationally expensive setup code should take place here.
*
* 6. Host finally checks the number of values, resolution, extents
* etc per output (which may vary depending on the number of channels,
* step size and block size as well as the parameter values).
*
* 7. Host will repeatedly call the process method to pass in blocks
* of input data. This method may return features extracted from that
* data (if the plugin is causal).
*
* 8. Host will call getRemainingFeatures exactly once, after all the
* input data has been processed. This may return any non-causal or
* leftover features.
*
* 9. At any point after initialise was called, the host may
* optionally call the reset method and restart processing. (This
* does not mean it can change the parameters, which are fixed from
* initialise until destruction.)
*
* A plugin does not need to handle the case where setParameter or
* selectProgram is called after initialise has been called. It's the
* host's responsibility not to do that. Similarly, the plugin may
* safely assume that initialise is called no more than once.
*/
class Plugin : public PluginBase
{
public:
virtual ~Plugin() { }
/**
* Initialise a plugin to prepare it for use with the given number
* of input channels, step size (window increment, in sample
* frames) and block size (window size, in sample frames).
*
* The input sample rate should have been already specified at
* construction time.
*
* Return true for successful initialisation, false if the number
* of input channels, step size and/or block size cannot be
* supported.
*/
virtual bool initialise(size_t inputChannels,
size_t stepSize,
size_t blockSize) = 0;
/**
* Reset the plugin after use, to prepare it for another clean
* run. Not called for the first initialisation (i.e. initialise
* must also do a reset).
*/
virtual void reset() = 0;
enum InputDomain { TimeDomain, FrequencyDomain };
/**
* Get the plugin's required input domain.
*
* If this is TimeDomain, the samples provided to the process()
* function (below) will be in the time domain, as for a
* traditional audio processing plugin.
*
* If this is FrequencyDomain, the host will carry out a windowed
* FFT of size equal to the negotiated block size on the data
* before passing the frequency bin data in to process(). The
* input data for the FFT will be rotated so as to place the
* origin in the centre of the block.
* The plugin does not get to choose the window type -- the host
* will either let the user do so, or will use a Hanning window.
*/
virtual InputDomain getInputDomain() const = 0;
/**
* Get the preferred block size (window size -- the number of
* sample frames passed in each block to the process() function).
* This should be called before initialise().
*
* A plugin that can handle any block size may return 0. The
* final block size will be set in the initialise() call.
*/
virtual size_t getPreferredBlockSize() const { return 0; }
/**
* Get the preferred step size (window increment -- the distance
* in sample frames between the start frames of consecutive blocks
* passed to the process() function) for the plugin. This should
* be called before initialise().
*
* A plugin may return 0 if it has no particular interest in the
* step size. In this case, the host should make the step size
* equal to the block size if the plugin is accepting input in the
* time domain. If the plugin is accepting input in the frequency
* domain, the host may use any step size. The final step size
* will be set in the initialise() call.
*/
virtual size_t getPreferredStepSize() const { return 0; }
/**
* Get the minimum supported number of input channels.
*/
virtual size_t getMinChannelCount() const { return 1; }
/**
* Get the maximum supported number of input channels.
*/
virtual size_t getMaxChannelCount() const { return 1; }
struct OutputDescriptor
{
/**
* The name of the output, in computer-usable form. Should be
* reasonably short and without whitespace or punctuation, using
* the characters [a-zA-Z0-9_-] only.
* Example: "zero_crossing_count"
*/
std::string identifier;
/**
* The human-readable name of the output.
* Example: "Zero Crossing Counts"
*/
std::string name;
/**
* A human-readable short text describing the output. May be
* empty if the name has said it all already.
* Example: "The number of zero crossing points per processing block"
*/
std::string description;
/**
* The unit of the output, in human-readable form.
*/
std::string unit;
/**
* True if the output has the same number of values per sample
* for every output sample. Outputs for which this is false
* are unlikely to be very useful in a general-purpose host.
*/
bool hasFixedBinCount;
/**
* The number of values per result of the output. Undefined
* if hasFixedBinCount is false. If this is zero, the output
* is point data (i.e. only the time of each output is of
* interest, the value list will be empty).
*/
size_t binCount;
/**
* The (human-readable) names of each of the bins, if
* appropriate. This is always optional.
*/
std::vector<std::string> binNames;
/**
* True if the results in each output bin fall within a fixed
* numeric range (minimum and maximum values). Undefined if
* binCount is zero.
*/
bool hasKnownExtents;
/**
* Minimum value of the results in the output. Undefined if
* hasKnownExtents is false or binCount is zero.
*/
float minValue;
/**
* Maximum value of the results in the output. Undefined if
* hasKnownExtents is false or binCount is zero.
*/
float maxValue;
/**
* True if the output values are quantized to a particular
* resolution. Undefined if binCount is zero.
*/
bool isQuantized;
/**
* Quantization resolution of the output values (e.g. 1.0 if
* they are all integers). Undefined if isQuantized is false
* or binCount is zero.
*/
float quantizeStep;
enum SampleType {
/// Results from each process() align with that call's block start
OneSamplePerStep,
/// Results are evenly spaced in time (sampleRate specified below)
FixedSampleRate,
/// Results are unevenly spaced and have individual timestamps
VariableSampleRate
};
/**
* Positioning in time of the output results.
*/
SampleType sampleType;
/**
* Sample rate of the output results, as samples per second.
* Undefined if sampleType is OneSamplePerStep.
*
* If sampleType is VariableSampleRate and this value is
* non-zero, then it may be used to calculate a resolution for
* the output (i.e. the "duration" of each sample, in time,
* will be 1/sampleRate seconds). It's recommended to set
* this to zero if that behaviour is not desired.
*/
float sampleRate;
/**
* True if the returned results for this output are known to
* have a duration field.
*/
bool hasDuration;
OutputDescriptor() : // defaults for mandatory non-class-type members
hasFixedBinCount(false), hasKnownExtents(false), isQuantized(false),
sampleType(OneSamplePerStep), hasDuration(false) { }
};
typedef std::vector<OutputDescriptor> OutputList;
/**
* Get the outputs of this plugin. An output's index in this list
* is used as its numeric index when looking it up in the
* FeatureSet returned from the process() call.
*/
virtual OutputList getOutputDescriptors() const = 0;
struct Feature
{
/**
* True if an output feature has its own timestamp. This is
* mandatory if the output has VariableSampleRate, optional if
* the output has FixedSampleRate, and unused if the output
* has OneSamplePerStep.
*/
bool hasTimestamp;
/**
* Timestamp of the output feature. This is mandatory if the
* output has VariableSampleRate or if the output has
* FixedSampleRate and hasTimestamp is true, and unused
* otherwise.
*/
RealTime timestamp;
/**
* True if an output feature has a specified duration. This
* is optional if the output has VariableSampleRate or
* FixedSampleRate, and and unused if the output has
* OneSamplePerStep.
*/
bool hasDuration;
/**
* Duration of the output feature. This is mandatory if the
* output has VariableSampleRate or FixedSampleRate and
* hasDuration is true, and unused otherwise.
*/
RealTime duration;
/**
* Results for a single sample of this feature. If the output
* hasFixedBinCount, there must be the same number of values
* as the output's binCount count.
*/
std::vector<float> values;
/**
* Label for the sample of this feature.
*/
std::string label;
Feature() : // defaults for mandatory non-class-type members
hasTimestamp(false), hasDuration(false) { }
};
typedef std::vector<Feature> FeatureList;
typedef std::map<int, FeatureList> FeatureSet; // key is output no
/**
* Process a single block of input data.
*
* If the plugin's inputDomain is TimeDomain, inputBuffers will
* point to one array of floats per input channel, and each of
* these arrays will contain blockSize consecutive audio samples
* (the host will zero-pad as necessary). The timestamp in this
* case will be the real time in seconds of the start of the
* supplied block of samples.
*
* If the plugin's inputDomain is FrequencyDomain, inputBuffers
* will point to one array of floats per input channel, and each
* of these arrays will contain blockSize/2+1 consecutive pairs of
* real and imaginary component floats corresponding to bins
* 0..(blockSize/2) of the FFT output. That is, bin 0 (the first
* pair of floats) contains the DC output, up to bin blockSize/2
* which contains the Nyquist-frequency output. There will
* therefore be blockSize+2 floats per channel in total. The
* timestamp will be the real time in seconds of the centre of the
* FFT input window (i.e. the very first block passed to process
* might contain the FFT of half a block of zero samples and the
* first half-block of the actual data, with a timestamp of zero).
*
* Return any features that have become available after this
* process call. (These do not necessarily have to fall within
* the process block, except for OneSamplePerStep outputs.)
*/
virtual FeatureSet process(const float *const *inputBuffers,
RealTime timestamp) = 0;
/**
* After all blocks have been processed, calculate and return any
* remaining features derived from the complete input.
*/
virtual FeatureSet getRemainingFeatures() = 0;
/**
* Used to distinguish between Vamp::Plugin and other potential
* sibling subclasses of PluginBase. Do not reimplement this
* function in your subclass.
*/
virtual std::string getType() const { return "Feature Extraction Plugin"; }
protected:
Plugin(float inputSampleRate) :
m_inputSampleRate(inputSampleRate) { }
float m_inputSampleRate;
};
}
_VAMP_SDK_PLUGSPACE_END(Plugin.h)
#endif

View File

@@ -1,121 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_PLUGIN_ADAPTER_H_
#define _VAMP_PLUGIN_ADAPTER_H_
#include <map>
#include "vamp/vamp.h"
#include "Plugin.h"
#include "plugguard.h"
_VAMP_SDK_PLUGSPACE_BEGIN(PluginAdapter.h)
namespace Vamp {
/**
* \class PluginAdapterBase PluginAdapter.h <vamp-sdk/PluginAdapter.h>
*
* PluginAdapter and PluginAdapterBase provide a wrapper class that a
* plugin library can use to make its C++ Vamp::Plugin objects
* available through the Vamp C API.
*
* Almost all Vamp plugin libraries will want to make use of this. To
* do so, all they need to do is declare a PluginAdapter<T> for each
* plugin class T in their library. It's very simple, and you need to
* know absolutely nothing about how it works in order to use it.
* Just cut and paste from an existing plugin's discovery function.
* \see vampGetPluginDescriptor
*/
class PluginAdapterBase
{
public:
virtual ~PluginAdapterBase();
/**
* Return a VampPluginDescriptor describing the plugin that is
* wrapped by this adapter.
*/
const VampPluginDescriptor *getDescriptor();
protected:
PluginAdapterBase();
virtual Plugin *createPlugin(float inputSampleRate) = 0;
class Impl;
Impl *m_impl;
};
/**
* \class PluginAdapter PluginAdapter.h <vamp-sdk/PluginAdapter.h>
*
* PluginAdapter turns a PluginAdapterBase into a specific wrapper for
* a particular plugin implementation.
*
* See PluginAdapterBase.
*/
template <typename P>
class PluginAdapter : public PluginAdapterBase
{
public:
PluginAdapter() : PluginAdapterBase() { }
virtual ~PluginAdapter() { }
protected:
Plugin *createPlugin(float inputSampleRate) {
P *p = new P(inputSampleRate);
Plugin *plugin = dynamic_cast<Plugin *>(p);
if (!plugin) {
std::cerr << "ERROR: PluginAdapter::createPlugin: "
<< "Template type is not a plugin!"
<< std::endl;
delete p;
return 0;
}
return plugin;
}
};
}
_VAMP_SDK_PLUGSPACE_END(PluginAdapter.h)
#endif

View File

@@ -1,262 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_SDK_PLUGIN_BASE_H_
#define _VAMP_SDK_PLUGIN_BASE_H_
#include <string>
#include <vector>
#define VAMP_SDK_VERSION "3.5"
#define VAMP_SDK_MAJOR_VERSION 2
#define VAMP_SDK_MINOR_VERSION 2
#include "plugguard.h"
_VAMP_SDK_PLUGSPACE_BEGIN(PluginBase.h)
namespace Vamp {
/**
* A base class for plugins with optional configurable parameters,
* programs, etc. The Vamp::Plugin is derived from this, and
* individual Vamp plugins should derive from that.
*
* This class does not provide the necessary interfaces to instantiate
* or run a plugin. It only specifies an interface for retrieving
* those controls that the host may wish to show to the user for
* editing. It could meaningfully be subclassed by real-time plugins
* or other sorts of plugin as well as Vamp plugins.
*/
class PluginBase
{
public:
virtual ~PluginBase() { }
/**
* Get the Vamp API compatibility level of the plugin.
*/
virtual unsigned int getVampApiVersion() const { return 2; }
/**
* Get the computer-usable name of the plugin. This should be
* reasonably short and contain no whitespace or punctuation
* characters. It may only contain the characters [a-zA-Z0-9_-].
* This is the authoritative way for a program to identify a
* plugin within a given library.
*
* This text may be visible to the user, but it should not be the
* main text used to identify a plugin to the user (that will be
* the name, below).
*
* Example: "zero_crossings"
*/
virtual std::string getIdentifier() const = 0;
/**
* Get a human-readable name or title of the plugin. This
* should be brief and self-contained, as it may be used to
* identify the plugin to the user in isolation (i.e. without also
* showing the plugin's "identifier").
*
* Example: "Zero Crossings"
*/
virtual std::string getName() const = 0;
/**
* Get a human-readable description for the plugin, typically
* a line of text that may optionally be displayed in addition
* to the plugin's "name". May be empty if the name has said
* it all already.
*
* Example: "Detect and count zero crossing points"
*/
virtual std::string getDescription() const = 0;
/**
* Get the name of the author or vendor of the plugin in
* human-readable form. This should be a short identifying text,
* as it may be used to label plugins from the same source in a
* menu or similar.
*/
virtual std::string getMaker() const = 0;
/**
* Get the copyright statement or licensing summary for the
* plugin. This can be an informative text, without the same
* presentation constraints as mentioned for getMaker above.
*/
virtual std::string getCopyright() const = 0;
/**
* Get the version number of the plugin.
*/
virtual int getPluginVersion() const = 0;
struct ParameterDescriptor
{
/**
* The name of the parameter, in computer-usable form. Should
* be reasonably short, and may only contain the characters
* [a-zA-Z0-9_-].
*/
std::string identifier;
/**
* The human-readable name of the parameter.
*/
std::string name;
/**
* A human-readable short text describing the parameter. May be
* empty if the name has said it all already.
*/
std::string description;
/**
* The unit of the parameter, in human-readable form.
*/
std::string unit;
/**
* The minimum value of the parameter.
*/
float minValue;
/**
* The maximum value of the parameter.
*/
float maxValue;
/**
* The default value of the parameter. The plugin should
* ensure that parameters have this value on initialisation
* (i.e. the host is not required to explicitly set parameters
* if it wants to use their default values).
*/
float defaultValue;
/**
* True if the parameter values are quantized to a particular
* resolution.
*/
bool isQuantized;
/**
* Quantization resolution of the parameter values (e.g. 1.0
* if they are all integers). Undefined if isQuantized is
* false.
*/
float quantizeStep;
/**
* Names for the quantized values. If isQuantized is true,
* this may either be empty or contain one string for each of
* the quantize steps from minValue up to maxValue inclusive.
* Undefined if isQuantized is false.
*
* If these names are provided, they should be shown to the
* user in preference to the values themselves. The user may
* never see the actual numeric values unless they are also
* encoded in the names.
*/
std::vector<std::string> valueNames;
ParameterDescriptor() : // the defaults are invalid: you must set them
minValue(0), maxValue(0), defaultValue(0), isQuantized(false) { }
};
typedef std::vector<ParameterDescriptor> ParameterList;
/**
* Get the controllable parameters of this plugin.
*/
virtual ParameterList getParameterDescriptors() const {
return ParameterList();
}
/**
* Get the value of a named parameter. The argument is the identifier
* field from that parameter's descriptor.
*/
virtual float getParameter(std::string) const { return 0.0; }
/**
* Set a named parameter. The first argument is the identifier field
* from that parameter's descriptor.
*/
virtual void setParameter(std::string, float) { }
typedef std::vector<std::string> ProgramList;
/**
* Get the program settings available in this plugin. A program
* is a named shorthand for a set of parameter values; changing
* the program may cause the plugin to alter the values of its
* published parameters (and/or non-public internal processing
* parameters). The host should re-read the plugin's parameter
* values after setting a new program.
*
* The programs must have unique names.
*/
virtual ProgramList getPrograms() const { return ProgramList(); }
/**
* Get the current program.
*/
virtual std::string getCurrentProgram() const { return ""; }
/**
* Select a program. (If the given program name is not one of the
* available programs, do nothing.)
*/
virtual void selectProgram(std::string) { }
/**
* Get the type of plugin. This is to be implemented by the
* immediate subclass, not by actual plugins. Do not attempt to
* implement this in plugin code.
*/
virtual std::string getType() const = 0;
};
}
_VAMP_SDK_PLUGSPACE_END(PluginBase.h)
#endif

View File

@@ -1,167 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
/*
This is a modified version of a source file from the
Rosegarden MIDI and audio sequencer and notation editor.
This file copyright 2000-2006 Chris Cannam.
Relicensed by the author as detailed above.
*/
#ifndef _VAMP_REAL_TIME_H_
#define _VAMP_REAL_TIME_H_
#include <iostream>
#include <string>
#ifndef _WIN32
struct timeval;
#endif
#include "plugguard.h"
_VAMP_SDK_PLUGSPACE_BEGIN(RealTime.h)
namespace Vamp {
/**
* \class RealTime RealTime.h <vamp-sdk/RealTime.h>
*
* RealTime represents time values to nanosecond precision
* with accurate arithmetic and frame-rate conversion functions.
*/
struct RealTime
{
int sec;
int nsec;
int usec() const { return nsec / 1000; }
int msec() const { return nsec / 1000000; }
RealTime(): sec(0), nsec(0) {}
RealTime(int s, int n);
RealTime(const RealTime &r) :
sec(r.sec), nsec(r.nsec) { }
static RealTime fromSeconds(double sec);
static RealTime fromMilliseconds(int msec);
#ifndef _WIN32
static RealTime fromTimeval(const struct timeval &);
#endif
RealTime &operator=(const RealTime &r) {
sec = r.sec; nsec = r.nsec; return *this;
}
RealTime operator+(const RealTime &r) const {
return RealTime(sec + r.sec, nsec + r.nsec);
}
RealTime operator-(const RealTime &r) const {
return RealTime(sec - r.sec, nsec - r.nsec);
}
RealTime operator-() const {
return RealTime(-sec, -nsec);
}
bool operator <(const RealTime &r) const {
if (sec == r.sec) return nsec < r.nsec;
else return sec < r.sec;
}
bool operator >(const RealTime &r) const {
if (sec == r.sec) return nsec > r.nsec;
else return sec > r.sec;
}
bool operator==(const RealTime &r) const {
return (sec == r.sec && nsec == r.nsec);
}
bool operator!=(const RealTime &r) const {
return !(r == *this);
}
bool operator>=(const RealTime &r) const {
if (sec == r.sec) return nsec >= r.nsec;
else return sec >= r.sec;
}
bool operator<=(const RealTime &r) const {
if (sec == r.sec) return nsec <= r.nsec;
else return sec <= r.sec;
}
RealTime operator/(int d) const;
/**
* Return the ratio of two times.
*/
double operator/(const RealTime &r) const;
/**
* Return a human-readable debug-type string to full precision
* (probably not a format to show to a user directly)
*/
std::string toString() const;
/**
* Return a user-readable string to the nearest millisecond
* in a form like HH:MM:SS.mmm
*/
std::string toText(bool fixedDp = false) const;
/**
* Convert a RealTime into a sample frame at the given sample rate.
*/
static long realTime2Frame(const RealTime &r, unsigned int sampleRate);
/**
* Convert a sample frame at the given sample rate into a RealTime.
*/
static RealTime frame2RealTime(long frame, unsigned int sampleRate);
static const RealTime zeroTime;
};
std::ostream &operator<<(std::ostream &out, const RealTime &rt);
}
_VAMP_SDK_PLUGSPACE_END(RealTime.h)
#endif

View File

@@ -1,98 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_SDK_PLUGGUARD_H_
#define _VAMP_SDK_PLUGGUARD_H_
/**
* Normal usage should be:
*
* - Plugins include vamp-sdk/Plugin.h or vamp-sdk/PluginBase.h.
* These files include this header, which specifies an appropriate
* namespace for the plugin classes to avoid any risk of conflict
* with non-plugin class implementations in the host on load.
*
* - Hosts include vamp-hostsdk/Plugin.h, vamp-hostsdk/PluginBase.h,
* vamp-hostsdk/PluginHostAdapter, vamp-hostsdk/PluginLoader.h etc.
* These files include vamp-hostsdk/hostguard.h, which makes a note
* that we are in a host. A file such as vamp-hostsdk/Plugin.h
* then simply includes vamp-sdk/Plugin.h, and this guard header
* takes notice of the fact that it has been included from a host
* and leaves the plugin namespace unset.
*
* Problems will occur when a host includes files directly from the
* vamp-sdk directory. There are two reasons this might happen:
* mistake, perhaps owing to ignorance of the fact that this isn't
* allowed (particularly since it was the normal mechanism in v1 of
* the SDK); and a wish to incorporate plugin code directly into the
* host rather than having to load it.
*
* What if the host does include a vamp-sdk header by mistake? We can
* catch it if it's included before something from vamp-hostsdk. If
* it's included after something from vamp-hostsdk, it will work OK
* anyway. The remaining problem case is where nothing from
* vamp-hostsdk is included in the same file. We can't catch that.
*/
#ifndef _VAMP_IN_HOSTSDK
#define _VAMP_IN_PLUGINSDK 1
#ifdef _VAMP_NO_PLUGIN_NAMESPACE
#define _VAMP_SDK_PLUGSPACE_BEGIN(h)
#define _VAMP_SDK_PLUGSPACE_END(h)
#else
#ifdef _VAMP_PLUGIN_IN_HOST_NAMESPACE
#define _VAMP_SDK_PLUGSPACE_BEGIN(h) \
namespace _VampHost {
#define _VAMP_SDK_PLUGSPACE_END(h) \
} \
using namespace _VampHost;
#else
#define _VAMP_SDK_PLUGSPACE_BEGIN(h) \
namespace _VampPlugin {
#define _VAMP_SDK_PLUGSPACE_END(h) \
} \
using namespace _VampPlugin;
#endif
#endif
#endif
#endif

View File

@@ -1,46 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef _VAMP_SDK_SINGLE_INCLUDE_H_
#define _VAMP_SDK_SINGLE_INCLUDE_H_
#include "PluginBase.h"
#include "Plugin.h"
#include "RealTime.h"
#endif

View File

@@ -1,388 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Vamp
An API for audio analysis and feature extraction plugins.
Centre for Digital Music, Queen Mary, University of London.
Copyright 2006 Chris Cannam.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the names of the Centre for
Digital Music; Queen Mary, University of London; and Chris Cannam
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
*/
#ifndef VAMP_HEADER_INCLUDED
#define VAMP_HEADER_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
/**
* Plugin API version. This is incremented when a change is made that
* changes the binary layout of the descriptor records. When this
* happens, there should be a mechanism for retaining compatibility
* with older hosts and/or plugins.
*
* See also the vampApiVersion field in the plugin descriptor, and the
* hostApiVersion argument to the vampGetPluginDescriptor function.
*/
#define VAMP_API_VERSION 2
/**
* C language API for Vamp plugins.
*
* This is the formal plugin API for Vamp. Plugin authors may prefer
* to use the C++ classes provided in the Vamp plugin SDK, instead of
* using this API directly. There is an adapter class provided that
* makes C++ plugins available using this C API with relatively little
* work, and the C++ headers are more thoroughly documented.
*
* IMPORTANT: The comments in this file summarise the purpose of each
* of the declared fields and functions, but do not provide a complete
* guide to their permitted values and expected usage. Please refer
* to the C++ headers in the Vamp plugin SDK for further details and
* plugin lifecycle documentation.
*/
typedef struct _VampParameterDescriptor
{
/** Computer-usable name of the parameter. Must not change. [a-zA-Z0-9_] */
const char *identifier;
/** Human-readable name of the parameter. May be translatable. */
const char *name;
/** Human-readable short text about the parameter. May be translatable. */
const char *description;
/** Human-readable unit of the parameter. */
const char *unit;
/** Minimum value. */
float minValue;
/** Maximum value. */
float maxValue;
/** Default value. Plugin is responsible for setting this on initialise. */
float defaultValue;
/** 1 if parameter values are quantized to a particular resolution. */
int isQuantized;
/** Quantization resolution, if isQuantized. */
float quantizeStep;
/** Human-readable names of the values, if isQuantized. May be NULL. */
const char **valueNames;
} VampParameterDescriptor;
typedef enum
{
/** Each process call returns results aligned with call's block start. */
vampOneSamplePerStep,
/** Returned results are evenly spaced at samplerate specified below. */
vampFixedSampleRate,
/** Returned results have their own individual timestamps. */
vampVariableSampleRate
} VampSampleType;
typedef struct _VampOutputDescriptor
{
/** Computer-usable name of the output. Must not change. [a-zA-Z0-9_] */
const char *identifier;
/** Human-readable name of the output. May be translatable. */
const char *name;
/** Human-readable short text about the output. May be translatable. */
const char *description;
/** Human-readable name of the unit of the output. */
const char *unit;
/** 1 if output has equal number of values for each returned result. */
int hasFixedBinCount;
/** Number of values per result, if hasFixedBinCount. */
unsigned int binCount;
/** Names of returned value bins, if hasFixedBinCount. May be NULL. */
const char **binNames;
/** 1 if each returned value falls within the same fixed min/max range. */
int hasKnownExtents;
/** Minimum value for a returned result in any bin, if hasKnownExtents. */
float minValue;
/** Maximum value for a returned result in any bin, if hasKnownExtents. */
float maxValue;
/** 1 if returned results are quantized to a particular resolution. */
int isQuantized;
/** Quantization resolution for returned results, if isQuantized. */
float quantizeStep;
/** Time positioning method for returned results (see VampSampleType). */
VampSampleType sampleType;
/** Sample rate of returned results, if sampleType is vampFixedSampleRate.
"Resolution" of result, if sampleType is vampVariableSampleRate. */
float sampleRate;
/** 1 if the returned results for this output are known to have a
duration field.
This field is new in Vamp API version 2; it must not be tested
for plugins that report an older API version in their plugin
descriptor.
*/
int hasDuration;
} VampOutputDescriptor;
typedef struct _VampFeature
{
/** 1 if the feature has a timestamp (i.e. if vampVariableSampleRate). */
int hasTimestamp;
/** Seconds component of timestamp. */
int sec;
/** Nanoseconds component of timestamp. */
int nsec;
/** Number of values. Must be binCount if hasFixedBinCount. */
unsigned int valueCount;
/** Values for this returned sample. */
float *values;
/** Label for this returned sample. May be NULL. */
char *label;
} VampFeature;
typedef struct _VampFeatureV2
{
/** 1 if the feature has a duration. */
int hasDuration;
/** Seconds component of duratiion. */
int durationSec;
/** Nanoseconds component of duration. */
int durationNsec;
} VampFeatureV2;
typedef union _VampFeatureUnion
{
// sizeof(featureV1) >= sizeof(featureV2) for backward compatibility
VampFeature v1;
VampFeatureV2 v2;
} VampFeatureUnion;
typedef struct _VampFeatureList
{
/** Number of features in this feature list. */
unsigned int featureCount;
/** Features in this feature list. May be NULL if featureCount is
zero.
If present, this array must contain featureCount feature
structures for a Vamp API version 1 plugin, or 2*featureCount
feature unions for a Vamp API version 2 plugin.
The features returned by an API version 2 plugin must consist
of the same feature structures as in API version 1 for the
first featureCount array elements, followed by featureCount
unions that contain VampFeatureV2 structures (or NULL pointers
if no V2 feature structures are present).
*/
VampFeatureUnion *features;
} VampFeatureList;
typedef enum
{
vampTimeDomain,
vampFrequencyDomain
} VampInputDomain;
typedef void *VampPluginHandle;
typedef struct _VampPluginDescriptor
{
/** API version with which this descriptor is compatible. */
unsigned int vampApiVersion;
/** Computer-usable name of the plugin. Must not change. [a-zA-Z0-9_] */
const char *identifier;
/** Human-readable name of the plugin. May be translatable. */
const char *name;
/** Human-readable short text about the plugin. May be translatable. */
const char *description;
/** Human-readable name of plugin's author or vendor. */
const char *maker;
/** Version number of the plugin. */
int pluginVersion;
/** Human-readable summary of copyright or licensing for plugin. */
const char *copyright;
/** Number of parameter inputs. */
unsigned int parameterCount;
/** Fixed descriptors for parameter inputs. */
const VampParameterDescriptor **parameters;
/** Number of programs. */
unsigned int programCount;
/** Fixed names for programs. */
const char **programs;
/** Preferred input domain for audio input (time or frequency). */
VampInputDomain inputDomain;
/** Create and return a new instance of this plugin. */
VampPluginHandle (*instantiate)(const struct _VampPluginDescriptor *,
float inputSampleRate);
/** Destroy an instance of this plugin. */
void (*cleanup)(VampPluginHandle);
/** Initialise an instance following parameter configuration. */
int (*initialise)(VampPluginHandle,
unsigned int inputChannels,
unsigned int stepSize,
unsigned int blockSize);
/** Reset an instance, ready to use again on new input data. */
void (*reset)(VampPluginHandle);
/** Get a parameter value. */
float (*getParameter)(VampPluginHandle, int);
/** Set a parameter value. May only be called before initialise. */
void (*setParameter)(VampPluginHandle, int, float);
/** Get the current program (if programCount > 0). */
unsigned int (*getCurrentProgram)(VampPluginHandle);
/** Set the current program. May only be called before initialise. */
void (*selectProgram)(VampPluginHandle, unsigned int);
/** Get the plugin's preferred processing window increment in samples. */
unsigned int (*getPreferredStepSize)(VampPluginHandle);
/** Get the plugin's preferred processing window size in samples. */
unsigned int (*getPreferredBlockSize)(VampPluginHandle);
/** Get the minimum number of input channels this plugin can handle. */
unsigned int (*getMinChannelCount)(VampPluginHandle);
/** Get the maximum number of input channels this plugin can handle. */
unsigned int (*getMaxChannelCount)(VampPluginHandle);
/** Get the number of feature outputs (distinct sets of results). */
unsigned int (*getOutputCount)(VampPluginHandle);
/** Get a descriptor for a given feature output. Returned pointer
is valid only until next call to getOutputDescriptor for this
handle, or releaseOutputDescriptor for this descriptor. Host
must call releaseOutputDescriptor after use. */
VampOutputDescriptor *(*getOutputDescriptor)(VampPluginHandle,
unsigned int);
/** Destroy a descriptor for a feature output. */
void (*releaseOutputDescriptor)(VampOutputDescriptor *);
/** Process an input block and return a set of features. Returned
pointer is valid only until next call to process,
getRemainingFeatures, or cleanup for this handle, or
releaseFeatureSet for this feature set. Host must call
releaseFeatureSet after use. */
VampFeatureList *(*process)(VampPluginHandle,
const float *const *inputBuffers,
int sec,
int nsec);
/** Return any remaining features at the end of processing. */
VampFeatureList *(*getRemainingFeatures)(VampPluginHandle);
/** Release a feature set returned from process or getRemainingFeatures. */
void (*releaseFeatureSet)(VampFeatureList *);
} VampPluginDescriptor;
/** Get the descriptor for a given plugin index in this library.
Return NULL if the index is outside the range of valid indices for
this plugin library.
The hostApiVersion argument tells the library code the highest
Vamp API version supported by the host. The function should
return a plugin descriptor compatible with the highest API version
supported by the library that is no higher than that supported by
the host. Provided the descriptor has the correct vampApiVersion
field for its actual compatibility level, the host should be able
to do the right thing with it: use it if possible, discard it
otherwise.
This is the only symbol that a Vamp plugin actually needs to
export from its shared object; all others can be hidden. See the
accompanying documentation for notes on how to achieve this with
certain compilers.
*/
const VampPluginDescriptor *vampGetPluginDescriptor
(unsigned int hostApiVersion, unsigned int index);
/** Function pointer type for vampGetPluginDescriptor. */
typedef const VampPluginDescriptor *(*VampGetPluginDescriptorFunction)
(unsigned int, unsigned int);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,10 +0,0 @@
prefix=%PREFIX%
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: vamp
Version: 1.0
Description: An API for audio analysis and feature extraction plugins
Libs:
Cflags: -I${includedir}

View File

@@ -1,73 +0,0 @@
#!/usr/bin/env python
from waflib.extras import autowaf as autowaf
import os
# Version of this package (even if built as a child)
LIBVAMP_VERSION = '0.0.0'
# Library version (UNIX style major, minor, micro)
# major increment <=> incompatible changes
# minor increment <=> compatible changes (additions)
# micro increment <=> no interface changes
LIBVAMP_LIB_VERSION = '0.0.0'
# Variables for 'waf dist'
APPNAME = 'libvamp'
VERSION = LIBVAMP_VERSION
# Mandatory variables
top = '.'
out = 'build'
def options(opt):
autowaf.set_options(opt)
def configure(conf):
if conf.is_defined('USE_EXTERNAL_LIBS'):
autowaf.check_pkg(conf, 'vamp-sdk', uselib_store='VAMPSDK', mandatory=True)
autowaf.check_pkg(conf, 'vamp-hostsdk', uselib_store='VAMPHOSTSDK', mandatory=True)
else:
conf.load('compiler_cxx')
autowaf.configure(conf)
autowaf.check_pkg(conf, 'fftw3', uselib_store='FFTW3', mandatory=True)
autowaf.check_pkg(conf, 'fftw3f', uselib_store='FFTW3F', mandatory=True)
conf.env.append_value('CXXFLAGS', '-DHAVE_FFTW3')
def build(bld):
if bld.is_defined('USE_EXTERNAL_LIBS'):
return
# Host Library
obj = bld(features = 'cxx cxxshlib')
obj.source = '''
src/vamp-hostsdk/PluginHostAdapter.cpp
src/vamp-hostsdk/PluginBufferingAdapter.cpp
src/vamp-hostsdk/PluginChannelAdapter.cpp
src/vamp-hostsdk/PluginInputDomainAdapter.cpp
src/vamp-hostsdk/PluginLoader.cpp
src/vamp-hostsdk/PluginWrapper.cpp
src/vamp-hostsdk/RealTime.cpp
'''
obj.export_includes = ['.']
obj.includes = ['.']
obj.name = 'libvamphost'
obj.target = 'vamphost'
obj.uselib = 'FFTW3 FFTW3F'
obj.vnum = LIBVAMP_LIB_VERSION
obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
# Plugin Library
obj = bld(features = 'cxx cxxshlib')
obj.source = '''
src/vamp-sdk/PluginAdapter.cpp
src/vamp-sdk/RealTime.cpp
'''
obj.export_includes = ['.']
obj.includes = ['.']
obj.name = 'libvampplugin'
obj.target = 'vampplugin'
obj.uselib = 'FFTW3 FFTW3F'
obj.vnum = LIBVAMP_LIB_VERSION
obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
def shutdown():
autowaf.shutdown()

24
wscript
View File

@@ -52,11 +52,9 @@ out = 'build'
children = [
# optionally external libraries
'libs/vamp-sdk',
'libs/qm-dsp',
'libs/vamp-plugins',
'libs/libltc',
'libs/rubberband',
# core ardour libraries
'libs/pbd',
'libs/midi++2',
@@ -653,14 +651,17 @@ def configure(conf):
okmsg = 'ok',
errmsg = 'too old\nPlease install boost version 1.39 or higher.')
autowaf.check_pkg(conf, 'glib-2.0', uselib_store='GLIB', atleast_version='2.2')
autowaf.check_pkg(conf, 'gthread-2.0', uselib_store='GTHREAD', atleast_version='2.2')
autowaf.check_pkg(conf, 'glibmm-2.4', uselib_store='GLIBMM', atleast_version='2.32.0')
autowaf.check_pkg(conf, 'sndfile', uselib_store='SNDFILE', atleast_version='1.0.18')
autowaf.check_pkg(conf, 'giomm-2.4', uselib_store='GIOMM', atleast_version='2.2')
autowaf.check_pkg(conf, 'libcurl', uselib_store='CURL', atleast_version='7.0.0')
autowaf.check_pkg(conf, 'liblo', uselib_store='LO', atleast_version='0.26')
autowaf.check_pkg(conf, 'taglib', uselib_store='TAGLIB', atleast_version='1.6')
autowaf.check_pkg(conf, 'glib-2.0', uselib_store='GLIB', atleast_version='2.2', mandatory=True)
autowaf.check_pkg(conf, 'gthread-2.0', uselib_store='GTHREAD', atleast_version='2.2', mandatory=True)
autowaf.check_pkg(conf, 'glibmm-2.4', uselib_store='GLIBMM', atleast_version='2.32.0', mandatory=True)
autowaf.check_pkg(conf, 'sndfile', uselib_store='SNDFILE', atleast_version='1.0.18, mandatory=True')
autowaf.check_pkg(conf, 'giomm-2.4', uselib_store='GIOMM', atleast_version='2.2', mandatory=True)
autowaf.check_pkg(conf, 'libcurl', uselib_store='CURL', atleast_version='7.0.0', mandatory=True)
autowaf.check_pkg(conf, 'liblo', uselib_store='LO', atleast_version='0.26', mandatory=True)
autowaf.check_pkg(conf, 'taglib', uselib_store='TAGLIB', atleast_version='1.6', mandatory=True)
autowaf.check_pkg(conf, 'vamp-sdk', uselib_store='VAMPSDK', atleast_version='2.4', mandatory=True)
autowaf.check_pkg(conf, 'vamp-hostsdk', uselib_store='VAMPHOSTSDK', atleast_version='2.4', mandatory=True)
autowaf.check_pkg(conf, 'rubberband', uselib_store='RUBBERBAND', mandatory=True)
if Options.options.dist_target == 'mingw':
Options.options.fpu_optimization = False
@@ -804,7 +805,6 @@ const char* const ardour_config_info = "\\n\\
write_config_text('OGG', conf.is_defined('HAVE_OGG'))
write_config_text('Phone home', conf.is_defined('PHONE_HOME'))
write_config_text('Program name', opts.program_name)
write_config_text('Rubberband', conf.is_defined('HAVE_RUBBERBAND'))
write_config_text('Samplerate', conf.is_defined('HAVE_SAMPLERATE'))
# write_config_text('Soundtouch', conf.is_defined('HAVE_SOUNDTOUCH'))
write_config_text('Translation', opts.nls)
@@ -830,9 +830,7 @@ def build(bld):
# add directories that contain only headers, to workaround an issue with waf
if not bld.is_defined('USE_EXTERNAL_LIBS'):
bld.path.find_dir ('libs/vamp-sdk/vamp-sdk')
bld.path.find_dir ('libs/libltc/ltc')
bld.path.find_dir ('libs/rubberband/rubberband')
bld.path.find_dir ('libs/evoral/evoral')
bld.path.find_dir ('libs/surfaces/control_protocol/control_protocol')
bld.path.find_dir ('libs/timecode/timecode')