diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2008-01-10 13:47:50 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2008-01-10 13:47:50 +0000 |
commit | 051d64131f583043d7b322d5aba600a45b0372ea (patch) | |
tree | 05a2983354cb7a806b2a3cffcf9a06e3b3d2fabd /libs/vamp-sdk | |
parent | b3e24ac78fa963202fcb6f3799039b05864687e0 (diff) |
bringing vamp-sdk into 2.0-ongoing branch
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@2867 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/vamp-sdk')
39 files changed, 8747 insertions, 0 deletions
diff --git a/libs/vamp-sdk/COPYING b/libs/vamp-sdk/COPYING new file mode 100644 index 0000000000..19fa472218 --- /dev/null +++ b/libs/vamp-sdk/COPYING @@ -0,0 +1,26 @@ + + 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. + diff --git a/libs/vamp-sdk/Doxyfile b/libs/vamp-sdk/Doxyfile new file mode 100644 index 0000000000..e8dfca34c8 --- /dev/null +++ b/libs/vamp-sdk/Doxyfile @@ -0,0 +1,1235 @@ +# Doxyfile 1.4.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = Vamp Plugin SDK + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 1.1 + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = YES + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is YES. + +SHOW_DIRECTORIES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the progam writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = docs/doxygen/warning.log + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = vamp vamp-sdk vamp-sdk/hostext examples host + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm + +FILE_PATTERNS = *.h \ + *.C \ + *.cpp \ + *.cc \ + doc-overview + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = qrc_*.cpp \ + moc_*.cpp \ + *.moc.cpp \ + *_skel.cpp + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +#USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 3 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = NO + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = HAVE_FFTW3F HAVE_FISHSOUND HAVE_JACK HAVE_LIBLO HAVE_LRDF HAVE_MAD HAVE_OGGZ HAVE_PORTAUDIO HAVE_SAMPLERATE HAVE_SNDFILE HAVE_VAMP + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = NO + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = NO + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that a graph may be further truncated if the graph's +# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH +# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default), +# the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/libs/vamp-sdk/Makefile b/libs/vamp-sdk/Makefile new file mode 100644 index 0000000000..5253ff4e21 --- /dev/null +++ b/libs/vamp-sdk/Makefile @@ -0,0 +1,249 @@ + +# Makefile for the Vamp plugin SDK. This builds the SDK objects, +# libraries, example plugins, and the test host. Please adjust to +# suit your operating system requirements. + +APIDIR = vamp +SDKDIR = vamp-sdk +HOSTEXTDIR = vamp-sdk/hostext +EXAMPLEDIR = examples +HOSTDIR = host + +### +### Start of user-serviceable parts +### + +# Default build target (or use "make <target>" to select one). +# Targets are: +# all -- build everything +# sdk -- build all the Vamp SDK libraries for plugins and hosts +# sdkstatic -- build only the static versions of the SDK libraries +# plugins -- build the example plugins (and the SDK if required) +# host -- build the simple Vamp plugin host (and the SDK if required) +# test -- build the host and example plugins, and run a quick test +# clean -- remove binary targets +# distclean -- remove all targets +# +default: all + +# Compile flags +# +CXXFLAGS := $(CXXFLAGS) -O2 -Wall -I. -fpic + +# ar, ranlib +# +AR := ar +RANLIB := ranlib + +# Libraries required for the plugins. +# (Note that it is desirable to statically link libstdc++ if possible, +# because our plugin exposes only a C API so there are no boundary +# compatibility problems.) +# +PLUGIN_LIBS = $(SDKDIR)/libvamp-sdk.a +#PLUGIN_LIBS = $(SDKDIR)/libvamp-sdk.a $(shell g++ -print-file-name=libstdc++.a) + +# File extension for a dynamically loadable object +# +PLUGIN_EXT = .so +#PLUGIN_EXT = .dll +#PLUGIN_EXT = .dylib + +# Libraries required for the host. +# +HOST_LIBS = $(SDKDIR)/libvamp-hostsdk.a -lsndfile -ldl + +# Locations for "make install". This will need quite a bit of +# editing for non-Linux platforms. Of course you don't necessarily +# have to use "make install". +# +INSTALL_PREFIX := /usr +INSTALL_API_HEADERS := $(INSTALL_PREFIX)/include/vamp +INSTALL_SDK_HEADERS := $(INSTALL_PREFIX)/include/vamp-sdk +INSTALL_HOSTEXT_HEADERS := $(INSTALL_PREFIX)/include/vamp-sdk/hostext +INSTALL_SDK_LIBS := $(INSTALL_PREFIX)/lib + +INSTALL_SDK_LIBNAME := libvamp-sdk.so.1.1.0 +INSTALL_SDK_LINK_ABI := libvamp-sdk.so.1 +INSTALL_SDK_LINK_DEV := libvamp-sdk.so +INSTALL_SDK_STATIC := libvamp-sdk.a +INSTALL_SDK_LA := libvamp-sdk.la + +INSTALL_HOSTSDK_LIBNAME := libvamp-hostsdk.so.2.0.0 +INSTALL_HOSTSDK_LINK_ABI := libvamp-hostsdk.so.2 +INSTALL_HOSTSDK_LINK_DEV := libvamp-hostsdk.so +INSTALL_HOSTSDK_STATIC := libvamp-hostsdk.a +INSTALL_HOSTSDK_LA := libvamp-hostsdk.la + +INSTALL_PKGCONFIG := $(INSTALL_PREFIX)/lib/pkgconfig + +# Flags required to tell the compiler to create a dynamically loadable object +# +DYNAMIC_LDFLAGS = -shared -Wl,-Bsymbolic +PLUGIN_LDFLAGS = $(DYNAMIC_LDFLAGS) +SDK_DYNAMIC_LDFLAGS = $(DYNAMIC_LDFLAGS) -Wl,-soname=$(INSTALL_SDK_LIBNAME) +HOSTSDK_DYNAMIC_LDFLAGS = $(DYNAMIC_LDFLAGS) -Wl,-soname=$(INSTALL_HOSTSDK_LIBNAME) + +## For OS/X with g++: +#PLUGIN_LDFLAGS = -dynamiclib + + +### End of user-serviceable parts + + +API_HEADERS = \ + $(APIDIR)/vamp.h + +SDK_HEADERS = \ + $(SDKDIR)/Plugin.h \ + $(SDKDIR)/PluginAdapter.h \ + $(SDKDIR)/PluginBase.h \ + $(SDKDIR)/RealTime.h + +HOSTSDK_HEADERS = \ + $(SDKDIR)/Plugin.h \ + $(SDKDIR)/PluginBase.h \ + $(SDKDIR)/PluginHostAdapter.h \ + $(SDKDIR)/RealTime.h + +HOSTEXT_HEADERS = \ + $(HOSTEXTDIR)/PluginChannelAdapter.h \ + $(HOSTEXTDIR)/PluginInputDomainAdapter.h \ + $(HOSTEXTDIR)/PluginLoader.h \ + $(HOSTEXTDIR)/PluginWrapper.h + +SDK_OBJECTS = \ + $(SDKDIR)/PluginAdapter.o \ + $(SDKDIR)/RealTime.o + +HOSTSDK_OBJECTS = \ + $(SDKDIR)/PluginHostAdapter.o \ + $(HOSTEXTDIR)/PluginChannelAdapter.o \ + $(HOSTEXTDIR)/PluginInputDomainAdapter.o \ + $(HOSTEXTDIR)/PluginLoader.o \ + $(HOSTEXTDIR)/PluginWrapper.o \ + $(SDKDIR)/RealTime.o + +SDK_STATIC = \ + $(SDKDIR)/libvamp-sdk.a + +HOSTSDK_STATIC = \ + $(SDKDIR)/libvamp-hostsdk.a + +SDK_DYNAMIC = \ + $(SDKDIR)/libvamp-sdk.so + +HOSTSDK_DYNAMIC = \ + $(SDKDIR)/libvamp-hostsdk.so + +SDK_LA = \ + $(SDKDIR)/libvamp-sdk.la + +HOSTSDK_LA = \ + $(SDKDIR)/libvamp-hostsdk.la + +PLUGIN_HEADERS = \ + $(EXAMPLEDIR)/SpectralCentroid.h \ + $(EXAMPLEDIR)/PercussionOnsetDetector.h \ + $(EXAMPLEDIR)/AmplitudeFollower.h \ + $(EXAMPLEDIR)/ZeroCrossing.h + +PLUGIN_OBJECTS = \ + $(EXAMPLEDIR)/SpectralCentroid.o \ + $(EXAMPLEDIR)/PercussionOnsetDetector.o \ + $(EXAMPLEDIR)/AmplitudeFollower.o \ + $(EXAMPLEDIR)/ZeroCrossing.o \ + $(EXAMPLEDIR)/plugins.o + +PLUGIN_TARGET = \ + $(EXAMPLEDIR)/vamp-example-plugins$(PLUGIN_EXT) + +HOST_HEADERS = \ + $(HOSTDIR)/system.h + +HOST_OBJECTS = \ + $(HOSTDIR)/vamp-simple-host.o + +HOST_TARGET = \ + $(HOSTDIR)/vamp-simple-host + +sdk: sdkstatic $(SDK_DYNAMIC) $(HOSTSDK_DYNAMIC) + +sdkstatic: $(SDK_STATIC) $(HOSTSDK_STATIC) + $(RANLIB) $(SDK_STATIC) + $(RANLIB) $(HOSTSDK_STATIC) + +plugins: $(PLUGIN_TARGET) + +host: $(HOST_TARGET) + +all: sdk plugins host test + +$(SDK_STATIC): $(SDK_OBJECTS) $(API_HEADERS) $(SDK_HEADERS) + $(AR) r $@ $(SDK_OBJECTS) + +$(HOSTSDK_STATIC): $(HOSTSDK_OBJECTS) $(API_HEADERS) $(HOSTSDK_HEADERS) $(HOSTEXT_HEADERS) + $(AR) r $@ $(HOSTSDK_OBJECTS) + +$(SDK_DYNAMIC): $(SDK_OBJECTS) $(API_HEADERS) $(SDK_HEADERS) + $(CXX) $(LDFLAGS) $(SDK_DYNAMIC_LDFLAGS) -o $@ $(SDK_OBJECTS) + +$(HOSTSDK_DYNAMIC): $(HOSTSDK_OBJECTS) $(API_HEADERS) $(HOSTSDK_HEADERS) $(HOSTEXT_HEADERS) + $(CXX) $(LDFLAGS) $(HOSTSDK_DYNAMIC_LDFLAGS) -o $@ $(HOSTSDK_OBJECTS) + +$(PLUGIN_TARGET): $(PLUGIN_OBJECTS) $(SDK_STATIC) $(PLUGIN_HEADERS) + $(CXX) $(LDFLAGS) $(PLUGIN_LDFLAGS) -o $@ $(PLUGIN_OBJECTS) $(PLUGIN_LIBS) + +$(HOST_TARGET): $(HOST_OBJECTS) $(HOSTSDK_STATIC) $(HOST_HEADERS) + $(CXX) $(LDFLAGS) $(HOST_LDFLAGS) -o $@ $(HOST_OBJECTS) $(HOST_LIBS) + +test: plugins host + VAMP_PATH=$(EXAMPLEDIR) $(HOST_TARGET) -l + +clean: + rm -f $(SDK_OBJECTS) $(HOSTSDK_OBJECTS) $(PLUGIN_OBJECTS) $(HOST_OBJECTS) + +distclean: clean + rm -f $(SDK_STATIC) $(SDK_DYNAMIC) $(HOSTSDK_STATIC) $(HOSTSDK_DYNAMIC) $(PLUGIN_TARGET) $(HOST_TARGET) *~ */*~ + +install: $(SDK_STATIC) $(SDK_DYNAMIC) $(HOSTSDK_STATIC) $(HOSTSDK_DYNAMIC) $(PLUGIN_TARGET) $(HOST_TARGET) + mkdir -p $(INSTALL_API_HEADERS) + mkdir -p $(INSTALL_SDK_HEADERS) + mkdir -p $(INSTALL_HOSTEXT_HEADERS) + mkdir -p $(INSTALL_SDK_LIBS) + mkdir -p $(INSTALL_PKGCONFIG) + cp $(API_HEADERS) $(INSTALL_API_HEADERS) + cp $(SDK_HEADERS) $(INSTALL_SDK_HEADERS) + cp $(HOSTSDK_HEADERS) $(INSTALL_SDK_HEADERS) + cp $(HOSTEXT_HEADERS) $(INSTALL_HOSTEXT_HEADERS) + cp $(SDK_STATIC) $(INSTALL_SDK_LIBS) + cp $(HOSTSDK_STATIC) $(INSTALL_SDK_LIBS) + cp $(SDK_DYNAMIC) $(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LIBNAME) + cp $(HOSTSDK_DYNAMIC) $(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LIBNAME) + rm -f $(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LINK_ABI) + ln -s $(INSTALL_SDK_LIBNAME) $(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LINK_ABI) + rm -f $(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LINK_ABI) + ln -s $(INSTALL_HOSTSDK_LIBNAME) $(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LINK_ABI) + rm -f $(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LINK_DEV) + ln -s $(INSTALL_SDK_LIBNAME) $(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LINK_DEV) + rm -f $(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LINK_DEV) + ln -s $(INSTALL_HOSTSDK_LIBNAME) $(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LINK_DEV) + sed "s,%PREFIX%,$(INSTALL_PREFIX)," $(APIDIR)/vamp.pc.in \ + > $(INSTALL_PKGCONFIG)/vamp.pc + sed "s,%PREFIX%,$(INSTALL_PREFIX)," $(SDKDIR)/vamp-sdk.pc.in \ + > $(INSTALL_PKGCONFIG)/vamp-sdk.pc + sed "s,%PREFIX%,$(INSTALL_PREFIX)," $(SDKDIR)/vamp-hostsdk.pc.in \ + > $(INSTALL_PKGCONFIG)/vamp-hostsdk.pc + sed -e "s,%LIBNAME%,$(INSTALL_SDK_LIBNAME),g" \ + -e "s,%LINK_ABI%,$(INSTALL_SDK_LINK_ABI),g" \ + -e "s,%LINK_DEV%,$(INSTALL_SDK_LINK_DEV),g" \ + -e "s,%STATIC%,$(INSTALL_SDK_STATIC),g" \ + -e "s,%LIBS%,$(INSTALL_SDK_LIBS),g" $(SDK_LA).in \ + > $(INSTALL_SDK_LIBS)/$(INSTALL_SDK_LA) + sed -e "s,%LIBNAME%,$(INSTALL_HOSTSDK_LIBNAME),g" \ + -e "s,%LINK_ABI%,$(INSTALL_HOSTSDK_LINK_ABI),g" \ + -e "s,%LINK_DEV%,$(INSTALL_HOSTSDK_LINK_DEV),g" \ + -e "s,%STATIC%,$(INSTALL_HOSTSDK_STATIC),g" \ + -e "s,%LIBS%,$(INSTALL_SDK_LIBS),g" $(HOSTSDK_LA).in \ + > $(INSTALL_SDK_LIBS)/$(INSTALL_HOSTSDK_LA) + diff --git a/libs/vamp-sdk/README b/libs/vamp-sdk/README new file mode 100644 index 0000000000..9454038260 --- /dev/null +++ b/libs/vamp-sdk/README @@ -0,0 +1,240 @@ + +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). + diff --git a/libs/vamp-sdk/examples/AmplitudeFollower.cpp b/libs/vamp-sdk/examples/AmplitudeFollower.cpp new file mode 100644 index 0000000000..7023297d33 --- /dev/null +++ b/libs/vamp-sdk/examples/AmplitudeFollower.cpp @@ -0,0 +1,247 @@ +/* -*- 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. + This file copyright 2006 Dan Stowell. + + 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 "AmplitudeFollower.h" + +#include <cmath> + +#include <string> +#include <vector> +#include <iostream> + +using std::string; +using std::vector; +using std::cerr; +using std::endl; + +/** + * An implementation of SuperCollider's amplitude-follower algorithm + * as a simple Vamp plugin. + */ + +AmplitudeFollower::AmplitudeFollower(float inputSampleRate) : + Plugin(inputSampleRate), + m_stepSize(0), + m_previn(0.0f), + m_clampcoef(0.01f), + m_relaxcoef(0.01f) +{ +} + +AmplitudeFollower::~AmplitudeFollower() +{ +} + +string +AmplitudeFollower::getIdentifier() const +{ + return "amplitudefollower"; +} + +string +AmplitudeFollower::getName() const +{ + return "Amplitude Follower"; +} + +string +AmplitudeFollower::getDescription() const +{ + return "Track the amplitude of the audio signal"; +} + +string +AmplitudeFollower::getMaker() const +{ + return "Vamp SDK Example Plugins"; +} + +int +AmplitudeFollower::getPluginVersion() const +{ + return 1; +} + +string +AmplitudeFollower::getCopyright() const +{ + return "Code copyright 2006 Dan Stowell; method from SuperCollider. Freely redistributable (BSD license)"; +} + +bool +AmplitudeFollower::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + m_stepSize = std::min(stepSize, blockSize); + + // Translate the coefficients + // from their "convenient" 60dB convergence-time values + // to real coefficients + m_clampcoef = m_clampcoef==0.0 ? 0.0 : exp(log(0.1)/(m_clampcoef * m_inputSampleRate)); + m_relaxcoef = m_relaxcoef==0.0 ? 0.0 : exp(log(0.1)/(m_relaxcoef * m_inputSampleRate)); + + return true; +} + +void +AmplitudeFollower::reset() +{ + m_previn = 0.0f; +} + +AmplitudeFollower::OutputList +AmplitudeFollower::getOutputDescriptors() const +{ + OutputList list; + + OutputDescriptor sca; + sca.identifier = "amplitude"; + sca.name = "Amplitude"; + sca.description = ""; + sca.unit = "V"; + sca.hasFixedBinCount = true; + sca.binCount = 1; + sca.hasKnownExtents = false; + sca.isQuantized = false; + sca.sampleType = OutputDescriptor::OneSamplePerStep; + list.push_back(sca); + + return list; +} + +AmplitudeFollower::ParameterList +AmplitudeFollower::getParameterDescriptors() const +{ + ParameterList list; + + ParameterDescriptor att; + att.identifier = "attack"; + att.name = "Attack time"; + att.description = ""; + att.unit = "s"; + att.minValue = 0.0f; + att.maxValue = 1.f; + att.defaultValue = 0.01f; + att.isQuantized = false; + + list.push_back(att); + + ParameterDescriptor dec; + dec.identifier = "release"; + dec.name = "Release time"; + dec.description = ""; + dec.unit = "s"; + dec.minValue = 0.0f; + dec.maxValue = 1.f; + dec.defaultValue = 0.01f; + dec.isQuantized = false; + + list.push_back(dec); + + return list; +} + +void AmplitudeFollower::setParameter(std::string paramid, float newval) +{ + if (paramid == "attack") { + m_clampcoef = newval; + } else if (paramid == "release") { + m_relaxcoef = newval; + } +} + +float AmplitudeFollower::getParameter(std::string paramid) const +{ + if (paramid == "attack") { + return m_clampcoef; + } else if (paramid == "release") { + return m_relaxcoef; + } + + return 0.0f; +} + +AmplitudeFollower::FeatureSet +AmplitudeFollower::process(const float *const *inputBuffers, + Vamp::RealTime timestamp) +{ + if (m_stepSize == 0) { + cerr << "ERROR: AmplitudeFollower::process: " + << "AmplitudeFollower has not been initialised" + << endl; + return FeatureSet(); + } + + float previn = m_previn; + + FeatureSet returnFeatures; + + float val; + float peak = 0.0f; + + for (size_t i = 0; i < m_stepSize; ++i) { + + val = fabs(inputBuffers[0][i]); + + if (val < previn) { + val = val + (previn - val) * m_relaxcoef; + } else { + val = val + (previn - val) * m_clampcoef; + } + + if (val > peak) peak = val; + previn = val; + } + + m_previn = previn; + + // Now store the "feature" (peak amp) for this sample + Feature feature; + feature.hasTimestamp = false; + feature.values.push_back(peak); + returnFeatures[0].push_back(feature); + + return returnFeatures; +} + +AmplitudeFollower::FeatureSet +AmplitudeFollower::getRemainingFeatures() +{ + return FeatureSet(); +} + diff --git a/libs/vamp-sdk/examples/AmplitudeFollower.h b/libs/vamp-sdk/examples/AmplitudeFollower.h new file mode 100644 index 0000000000..6c3426e324 --- /dev/null +++ b/libs/vamp-sdk/examples/AmplitudeFollower.h @@ -0,0 +1,84 @@ +/* -*- 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. + This file copyright 2006 Dan Stowell. + + 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 _AMPLITUDE_FOLLOWER_PLUGIN_H_ +#define _AMPLITUDE_FOLLOWER_PLUGIN_H_ + +#include "vamp-sdk/Plugin.h" + +/** + * Example plugin implementing the SuperCollider amplitude follower + * function. + */ + +class AmplitudeFollower : public Vamp::Plugin +{ +public: + AmplitudeFollower(float inputSampleRate); + virtual ~AmplitudeFollower(); + + 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; + + OutputList getOutputDescriptors() const; + + ParameterList getParameterDescriptors() const; + float getParameter(std::string paramid) const; + void setParameter(std::string paramid, float newval); + + FeatureSet process(const float *const *inputBuffers, + Vamp::RealTime timestamp); + + FeatureSet getRemainingFeatures(); + +protected: + size_t m_stepSize; + float m_previn; + float m_clampcoef; + float m_relaxcoef; +}; + + +#endif diff --git a/libs/vamp-sdk/examples/PercussionOnsetDetector.cpp b/libs/vamp-sdk/examples/PercussionOnsetDetector.cpp new file mode 100644 index 0000000000..447eb19a28 --- /dev/null +++ b/libs/vamp-sdk/examples/PercussionOnsetDetector.cpp @@ -0,0 +1,285 @@ +/* -*- 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 "PercussionOnsetDetector.h" + +using std::string; +using std::vector; +using std::cerr; +using std::endl; + +#include <cmath> + + +PercussionOnsetDetector::PercussionOnsetDetector(float inputSampleRate) : + Plugin(inputSampleRate), + m_stepSize(0), + m_blockSize(0), + m_threshold(3), + m_sensitivity(40), + m_priorMagnitudes(0), + m_dfMinus1(0), + m_dfMinus2(0) +{ +} + +PercussionOnsetDetector::~PercussionOnsetDetector() +{ + delete[] m_priorMagnitudes; +} + +string +PercussionOnsetDetector::getIdentifier() const +{ + return "percussiononsets"; +} + +string +PercussionOnsetDetector::getName() const +{ + return "Simple Percussion Onset Detector"; +} + +string +PercussionOnsetDetector::getDescription() const +{ + return "Detect percussive note onsets by identifying broadband energy rises"; +} + +string +PercussionOnsetDetector::getMaker() const +{ + return "Vamp SDK Example Plugins"; +} + +int +PercussionOnsetDetector::getPluginVersion() const +{ + return 2; +} + +string +PercussionOnsetDetector::getCopyright() const +{ + return "Code copyright 2006 Queen Mary, University of London, after Dan Barry et al 2005. Freely redistributable (BSD license)"; +} + +size_t +PercussionOnsetDetector::getPreferredStepSize() const +{ + return 0; +} + +size_t +PercussionOnsetDetector::getPreferredBlockSize() const +{ + return 1024; +} + +bool +PercussionOnsetDetector::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + m_stepSize = stepSize; + m_blockSize = blockSize; + + m_priorMagnitudes = new float[m_blockSize/2]; + + for (size_t i = 0; i < m_blockSize/2; ++i) { + m_priorMagnitudes[i] = 0.f; + } + + m_dfMinus1 = 0.f; + m_dfMinus2 = 0.f; + + return true; +} + +void +PercussionOnsetDetector::reset() +{ + for (size_t i = 0; i < m_blockSize/2; ++i) { + m_priorMagnitudes[i] = 0.f; + } + + m_dfMinus1 = 0.f; + m_dfMinus2 = 0.f; +} + +PercussionOnsetDetector::ParameterList +PercussionOnsetDetector::getParameterDescriptors() const +{ + ParameterList list; + + ParameterDescriptor d; + d.identifier = "threshold"; + d.name = "Energy rise threshold"; + d.description = "Energy rise within a frequency bin necessary to count toward broadband total"; + d.unit = "dB"; + d.minValue = 0; + d.maxValue = 20; + d.defaultValue = 3; + d.isQuantized = false; + list.push_back(d); + + d.identifier = "sensitivity"; + d.name = "Sensitivity"; + d.description = "Sensitivity of peak detector applied to broadband detection function"; + d.unit = "%"; + d.minValue = 0; + d.maxValue = 100; + d.defaultValue = 40; + d.isQuantized = false; + list.push_back(d); + + return list; +} + +float +PercussionOnsetDetector::getParameter(std::string id) const +{ + if (id == "threshold") return m_threshold; + if (id == "sensitivity") return m_sensitivity; + return 0.f; +} + +void +PercussionOnsetDetector::setParameter(std::string id, float value) +{ + if (id == "threshold") { + if (value < 0) value = 0; + if (value > 20) value = 20; + m_threshold = value; + } else if (id == "sensitivity") { + if (value < 0) value = 0; + if (value > 100) value = 100; + m_sensitivity = value; + } +} + +PercussionOnsetDetector::OutputList +PercussionOnsetDetector::getOutputDescriptors() const +{ + OutputList list; + + OutputDescriptor d; + d.identifier = "onsets"; + d.name = "Onsets"; + d.description = "Percussive note onset locations"; + d.unit = ""; + d.hasFixedBinCount = true; + d.binCount = 0; + d.hasKnownExtents = false; + d.isQuantized = false; + d.sampleType = OutputDescriptor::VariableSampleRate; + d.sampleRate = m_inputSampleRate; + list.push_back(d); + + d.identifier = "detectionfunction"; + d.name = "Detection Function"; + d.description = "Broadband energy rise detection function"; + d.binCount = 1; + d.isQuantized = true; + d.quantizeStep = 1.0; + d.sampleType = OutputDescriptor::OneSamplePerStep; + list.push_back(d); + + return list; +} + +PercussionOnsetDetector::FeatureSet +PercussionOnsetDetector::process(const float *const *inputBuffers, + Vamp::RealTime ts) +{ + if (m_stepSize == 0) { + cerr << "ERROR: PercussionOnsetDetector::process: " + << "PercussionOnsetDetector has not been initialised" + << endl; + return FeatureSet(); + } + + int count = 0; + + for (size_t i = 1; i < m_blockSize/2; ++i) { + + float real = inputBuffers[0][i*2]; + float imag = inputBuffers[0][i*2 + 1]; + + float sqrmag = real * real + imag * imag; + + if (m_priorMagnitudes[i] > 0.f) { + float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]); + +// std::cout << "i=" << i << ", mag=" << mag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << std::endl; + + if (diff >= m_threshold) ++count; + } + + m_priorMagnitudes[i] = sqrmag; + } + + FeatureSet returnFeatures; + + Feature detectionFunction; + detectionFunction.hasTimestamp = false; + detectionFunction.values.push_back(count); + returnFeatures[1].push_back(detectionFunction); + + if (m_dfMinus2 < m_dfMinus1 && + m_dfMinus1 >= count && + m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) { + + Feature onset; + onset.hasTimestamp = true; + onset.timestamp = ts - Vamp::RealTime::frame2RealTime + (m_stepSize, lrintf(m_inputSampleRate)); + returnFeatures[0].push_back(onset); + } + + m_dfMinus2 = m_dfMinus1; + m_dfMinus1 = count; + + return returnFeatures; +} + +PercussionOnsetDetector::FeatureSet +PercussionOnsetDetector::getRemainingFeatures() +{ + return FeatureSet(); +} + diff --git a/libs/vamp-sdk/examples/PercussionOnsetDetector.h b/libs/vamp-sdk/examples/PercussionOnsetDetector.h new file mode 100644 index 0000000000..d54c0cfa13 --- /dev/null +++ b/libs/vamp-sdk/examples/PercussionOnsetDetector.h @@ -0,0 +1,90 @@ +/* -*- 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 _PERCUSSION_ONSET_DETECTOR_PLUGIN_H_ +#define _PERCUSSION_ONSET_DETECTOR_PLUGIN_H_ + +#include "vamp-sdk/Plugin.h" + +/** + * Example plugin that detects percussive events. + */ + +class PercussionOnsetDetector : public Vamp::Plugin +{ +public: + PercussionOnsetDetector(float inputSampleRate); + virtual ~PercussionOnsetDetector(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + void reset(); + + InputDomain getInputDomain() const { return FrequencyDomain; } + + std::string getIdentifier() const; + std::string getName() const; + std::string getDescription() const; + std::string getMaker() const; + int getPluginVersion() const; + std::string getCopyright() const; + + size_t getPreferredStepSize() const; + size_t getPreferredBlockSize() 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: + size_t m_stepSize; + size_t m_blockSize; + + float m_threshold; + float m_sensitivity; + float *m_priorMagnitudes; + float m_dfMinus1; + float m_dfMinus2; +}; + + +#endif diff --git a/libs/vamp-sdk/examples/SpectralCentroid.cpp b/libs/vamp-sdk/examples/SpectralCentroid.cpp new file mode 100644 index 0000000000..82d80b8100 --- /dev/null +++ b/libs/vamp-sdk/examples/SpectralCentroid.cpp @@ -0,0 +1,188 @@ +/* -*- 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 "SpectralCentroid.h" + +using std::string; +using std::vector; +using std::cerr; +using std::endl; + +#include <cmath> + + +SpectralCentroid::SpectralCentroid(float inputSampleRate) : + Plugin(inputSampleRate), + m_stepSize(0), + m_blockSize(0) +{ +} + +SpectralCentroid::~SpectralCentroid() +{ +} + +string +SpectralCentroid::getIdentifier() const +{ + return "spectralcentroid"; +} + +string +SpectralCentroid::getName() const +{ + return "Spectral Centroid"; +} + +string +SpectralCentroid::getDescription() const +{ + return "Calculate the centroid frequency of the spectrum of the input signal"; +} + +string +SpectralCentroid::getMaker() const +{ + return "Vamp SDK Example Plugins"; +} + +int +SpectralCentroid::getPluginVersion() const +{ + return 2; +} + +string +SpectralCentroid::getCopyright() const +{ + return "Freely redistributable (BSD license)"; +} + +bool +SpectralCentroid::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + m_stepSize = stepSize; + m_blockSize = blockSize; + + return true; +} + +void +SpectralCentroid::reset() +{ +} + +SpectralCentroid::OutputList +SpectralCentroid::getOutputDescriptors() const +{ + OutputList list; + + OutputDescriptor d; + d.identifier = "logcentroid"; + d.name = "Log Frequency Centroid"; + d.description = "Centroid of the log weighted frequency spectrum"; + d.unit = "Hz"; + d.hasFixedBinCount = true; + d.binCount = 1; + d.hasKnownExtents = false; + d.isQuantized = false; + d.sampleType = OutputDescriptor::OneSamplePerStep; + list.push_back(d); + + d.identifier = "linearcentroid"; + d.name = "Linear Frequency Centroid"; + d.description = "Centroid of the linear frequency spectrum"; + list.push_back(d); + + return list; +} + +SpectralCentroid::FeatureSet +SpectralCentroid::process(const float *const *inputBuffers, Vamp::RealTime) +{ + if (m_stepSize == 0) { + cerr << "ERROR: SpectralCentroid::process: " + << "SpectralCentroid has not been initialised" + << endl; + return FeatureSet(); + } + + double numLin = 0.0, numLog = 0.0, denom = 0.0; + + for (size_t i = 1; i <= m_blockSize/2; ++i) { + double freq = (double(i) * m_inputSampleRate) / m_blockSize; + double real = inputBuffers[0][i*2]; + double imag = inputBuffers[0][i*2 + 1]; + double power = sqrt(real * real + imag * imag) / (m_blockSize/2); + numLin += freq * power; + numLog += log10f(freq) * power; + denom += power; + } + + FeatureSet returnFeatures; + +// std::cerr << "power " << denom << ", block size " << m_blockSize << std::endl; + + if (denom != 0.0) { + float centroidLin = float(numLin / denom); + float centroidLog = powf(10, float(numLog / denom)); + + Feature feature; + feature.hasTimestamp = false; + if (!std::isnan(centroidLog) && !std::isinf(centroidLog)) { + feature.values.push_back(centroidLog); + } + returnFeatures[0].push_back(feature); + + feature.values.clear(); + if (!std::isnan(centroidLin) && !std::isinf(centroidLin)) { + feature.values.push_back(centroidLin); + } + returnFeatures[1].push_back(feature); + } + + return returnFeatures; +} + +SpectralCentroid::FeatureSet +SpectralCentroid::getRemainingFeatures() +{ + return FeatureSet(); +} + diff --git a/libs/vamp-sdk/examples/SpectralCentroid.h b/libs/vamp-sdk/examples/SpectralCentroid.h new file mode 100644 index 0000000000..02cc8d981d --- /dev/null +++ b/libs/vamp-sdk/examples/SpectralCentroid.h @@ -0,0 +1,78 @@ +/* -*- 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 _SPECTRAL_CENTROID_PLUGIN_H_ +#define _SPECTRAL_CENTROID_PLUGIN_H_ + +#include "vamp-sdk/Plugin.h" + +/** + * Example plugin that calculates the centre of gravity of the + * frequency domain representation of each block of audio. + */ + +class SpectralCentroid : public Vamp::Plugin +{ +public: + SpectralCentroid(float inputSampleRate); + virtual ~SpectralCentroid(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + void reset(); + + InputDomain getInputDomain() const { return FrequencyDomain; } + + std::string getIdentifier() const; + std::string getName() const; + std::string getDescription() const; + std::string getMaker() const; + int getPluginVersion() const; + std::string getCopyright() const; + + OutputList getOutputDescriptors() const; + + FeatureSet process(const float *const *inputBuffers, + Vamp::RealTime timestamp); + + FeatureSet getRemainingFeatures(); + +protected: + size_t m_stepSize; + size_t m_blockSize; +}; + + +#endif diff --git a/libs/vamp-sdk/examples/ZeroCrossing.cpp b/libs/vamp-sdk/examples/ZeroCrossing.cpp new file mode 100644 index 0000000000..4b678e3f8f --- /dev/null +++ b/libs/vamp-sdk/examples/ZeroCrossing.cpp @@ -0,0 +1,194 @@ +/* -*- 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 "ZeroCrossing.h" + +using std::string; +using std::vector; +using std::cerr; +using std::endl; + + +ZeroCrossing::ZeroCrossing(float inputSampleRate) : + Plugin(inputSampleRate), + m_stepSize(0), + m_previousSample(0.0f) +{ +} + +ZeroCrossing::~ZeroCrossing() +{ +} + +string +ZeroCrossing::getIdentifier() const +{ + return "zerocrossing"; +} + +string +ZeroCrossing::getName() const +{ + return "Zero Crossings"; +} + +string +ZeroCrossing::getDescription() const +{ + return "Detect and count zero crossing points"; +} + +string +ZeroCrossing::getMaker() const +{ + return "Vamp SDK Example Plugins"; +} + +int +ZeroCrossing::getPluginVersion() const +{ + return 2; +} + +string +ZeroCrossing::getCopyright() const +{ + return "Freely redistributable (BSD license)"; +} + +bool +ZeroCrossing::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + m_stepSize = std::min(stepSize, blockSize); + + return true; +} + +void +ZeroCrossing::reset() +{ + m_previousSample = 0.0f; +} + +ZeroCrossing::OutputList +ZeroCrossing::getOutputDescriptors() const +{ + OutputList list; + + OutputDescriptor zc; + zc.identifier = "counts"; + zc.name = "Zero Crossing Counts"; + zc.description = "The number of zero crossing points per processing block"; + zc.unit = "crossings"; + zc.hasFixedBinCount = true; + zc.binCount = 1; + zc.hasKnownExtents = false; + zc.isQuantized = true; + zc.quantizeStep = 1.0; + zc.sampleType = OutputDescriptor::OneSamplePerStep; + list.push_back(zc); + + zc.identifier = "zerocrossings"; + zc.name = "Zero Crossings"; + zc.description = "The locations of zero crossing points"; + zc.unit = ""; + zc.hasFixedBinCount = true; + zc.binCount = 0; + zc.sampleType = OutputDescriptor::VariableSampleRate; + zc.sampleRate = m_inputSampleRate; + list.push_back(zc); + + return list; +} + +ZeroCrossing::FeatureSet +ZeroCrossing::process(const float *const *inputBuffers, + Vamp::RealTime timestamp) +{ + if (m_stepSize == 0) { + cerr << "ERROR: ZeroCrossing::process: " + << "ZeroCrossing has not been initialised" + << endl; + return FeatureSet(); + } + + float prev = m_previousSample; + size_t count = 0; + + FeatureSet returnFeatures; + + for (size_t i = 0; i < m_stepSize; ++i) { + + float sample = inputBuffers[0][i]; + bool crossing = false; + + if (sample <= 0.0) { + if (prev > 0.0) crossing = true; + } else if (sample > 0.0) { + if (prev <= 0.0) crossing = true; + } + + if (crossing) { + ++count; + Feature feature; + feature.hasTimestamp = true; + feature.timestamp = timestamp + + Vamp::RealTime::frame2RealTime(i, (size_t)m_inputSampleRate); + returnFeatures[1].push_back(feature); + } + + prev = sample; + } + + m_previousSample = prev; + + Feature feature; + feature.hasTimestamp = false; + feature.values.push_back(count); + + returnFeatures[0].push_back(feature); + return returnFeatures; +} + +ZeroCrossing::FeatureSet +ZeroCrossing::getRemainingFeatures() +{ + return FeatureSet(); +} + diff --git a/libs/vamp-sdk/examples/ZeroCrossing.h b/libs/vamp-sdk/examples/ZeroCrossing.h new file mode 100644 index 0000000000..ede2a74492 --- /dev/null +++ b/libs/vamp-sdk/examples/ZeroCrossing.h @@ -0,0 +1,78 @@ +/* -*- 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 _ZERO_CROSSING_PLUGIN_H_ +#define _ZERO_CROSSING_PLUGIN_H_ + +#include "vamp-sdk/Plugin.h" + +/** + * Example plugin that calculates the positions and density of + * zero-crossing points in an audio waveform. +*/ + +class ZeroCrossing : public Vamp::Plugin +{ +public: + ZeroCrossing(float inputSampleRate); + virtual ~ZeroCrossing(); + + 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; + + OutputList getOutputDescriptors() const; + + FeatureSet process(const float *const *inputBuffers, + Vamp::RealTime timestamp); + + FeatureSet getRemainingFeatures(); + +protected: + size_t m_stepSize; + float m_previousSample; +}; + + +#endif diff --git a/libs/vamp-sdk/examples/plugins.cpp b/libs/vamp-sdk/examples/plugins.cpp new file mode 100644 index 0000000000..25c6e6c0d4 --- /dev/null +++ b/libs/vamp-sdk/examples/plugins.cpp @@ -0,0 +1,63 @@ +/* -*- 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/vamp.h" +#include "vamp-sdk/PluginAdapter.h" + +#include "ZeroCrossing.h" +#include "SpectralCentroid.h" +#include "PercussionOnsetDetector.h" +#include "AmplitudeFollower.h" + +static Vamp::PluginAdapter<ZeroCrossing> zeroCrossingAdapter; +static Vamp::PluginAdapter<SpectralCentroid> spectralCentroidAdapter; +static Vamp::PluginAdapter<PercussionOnsetDetector> percussionOnsetAdapter; +static Vamp::PluginAdapter<AmplitudeFollower> amplitudeAdapter; + +const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version, + unsigned int index) +{ + if (version < 1) return 0; + + switch (index) { + case 0: return zeroCrossingAdapter.getDescriptor(); + case 1: return spectralCentroidAdapter.getDescriptor(); + case 2: return percussionOnsetAdapter.getDescriptor(); + case 3: return amplitudeAdapter.getDescriptor(); + default: return 0; + } +} + diff --git a/libs/vamp-sdk/examples/vamp-example-plugins.cat b/libs/vamp-sdk/examples/vamp-example-plugins.cat new file mode 100644 index 0000000000..7676c4aca6 --- /dev/null +++ b/libs/vamp-sdk/examples/vamp-example-plugins.cat @@ -0,0 +1,5 @@ +vamp:vamp-example-plugins:zerocrossing::Low Level Features +vamp:vamp-example-plugins:spectralcentroid::Low Level Features +vamp:vamp-example-plugins:percussiononsets::Time > Onsets +vamp:vamp-example-plugins:amplitudefollower::Low Level Features + diff --git a/libs/vamp-sdk/host/system.h b/libs/vamp-sdk/host/system.h new file mode 100644 index 0000000000..15aa8c199f --- /dev/null +++ b/libs/vamp-sdk/host/system.h @@ -0,0 +1,75 @@ +/* -*- 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 _SYSTEM_H_ +#define _SYSTEM_H_ + +#ifdef _WIN32 + +#include <windows.h> + +#define DLOPEN(a,b) LoadLibrary((a).c_str()) +#define DLSYM(a,b) GetProcAddress((HINSTANCE)(a),(b)) +#define DLCLOSE(a) FreeLibrary((HINSTANCE)(a)) +#define DLERROR() "" + +#define PLUGIN_SUFFIX "dll" + +#else + +#include <dlfcn.h> + +#define DLOPEN(a,b) dlopen((a).c_str(),(b)) +#define DLSYM(a,b) dlsym((a),(b)) +#define DLCLOSE(a) dlclose((a)) +#define DLERROR() dlerror() + +#ifdef __APPLE__ + +#define PLUGIN_SUFFIX "dylib" +#define HAVE_OPENDIR 1 + +#else + +#define PLUGIN_SUFFIX "so" +#define HAVE_OPENDIR 1 + +#endif /* __APPLE__ */ + +#endif /* ! _WIN32 */ + +#endif + diff --git a/libs/vamp-sdk/host/vamp-simple-host.cpp b/libs/vamp-sdk/host/vamp-simple-host.cpp new file mode 100644 index 0000000000..c8ae28d81b --- /dev/null +++ b/libs/vamp-sdk/host/vamp-simple-host.cpp @@ -0,0 +1,492 @@ +/* -*- 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. + FFT code from 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-sdk/PluginHostAdapter.h" +#include "vamp-sdk/hostext/PluginChannelAdapter.h" +#include "vamp-sdk/hostext/PluginInputDomainAdapter.h" +#include "vamp-sdk/hostext/PluginLoader.h" +#include "vamp/vamp.h" + +#include <iostream> +#include <fstream> +#include <sndfile.h> + +#include "system.h" + +#include <cmath> + +using std::cout; +using std::cerr; +using std::endl; +using std::string; +using std::vector; +using std::ofstream; +using std::ios; + +using Vamp::HostExt::PluginLoader; + +#define HOST_VERSION "1.1" + +void printFeatures(int, int, int, Vamp::Plugin::FeatureSet, ofstream *); +void transformInput(float *, size_t); +void fft(unsigned int, bool, double *, double *, double *, double *); +void printPluginPath(bool verbose); +void enumeratePlugins(); +void listPluginsInLibrary(string soname); +int runPlugin(string myname, string soname, string id, string output, + int outputNo, string inputFile, string outfilename); + +void usage(const char *name) +{ + cerr << "\n" + << name << ": A simple Vamp plugin host.\n\n" + "Centre for Digital Music, Queen Mary, University of London.\n" + "Copyright 2006-2007 Chris Cannam and QMUL.\n" + "Freely redistributable; published under a BSD-style license.\n\n" + "Usage:\n\n" + " " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav [-o outfile.txt]\n" + " " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno] [-o outfile.txt]\n\n" + " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n" + " audio data in \"file.wav\", retrieving the named \"output\", or output\n" + " number \"outputno\" (the first output by default) and dumping it to\n" + " standard output, or to \"outfile.txt\" if the -o option is given.\n\n" + " \"pluginlibrary\" should be a library name, not a file path; the\n" + " standard Vamp library search path will be used to locate it. If\n" + " a file path is supplied, the directory part(s) will be ignored.\n\n" + " " << name << " -l\n\n" + " -- List the plugin libraries and Vamp plugins in the library search path.\n\n" + " " << name << " -p\n\n" + " -- Print out the Vamp library search path.\n\n" + " " << name << " -v\n\n" + " -- Display version information only.\n\n" + << endl; + exit(2); +} + +int main(int argc, char **argv) +{ + char *scooter = argv[0]; + char *name = 0; + while (scooter && *scooter) { + if (*scooter == '/' || *scooter == '\\') name = ++scooter; + else ++scooter; + } + if (!name || !*name) name = argv[0]; + + if (argc < 2) usage(name); + + if (argc == 2) { + + if (!strcmp(argv[1], "-v")) { + + cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl + << "Vamp API version: " << VAMP_API_VERSION << endl + << "Vamp SDK version: " << VAMP_SDK_VERSION << endl; + return 0; + + } else if (!strcmp(argv[1], "-l")) { + + printPluginPath(true); + enumeratePlugins(); + return 0; + + } else if (!strcmp(argv[1], "-p")) { + + printPluginPath(false); + return 0; + + } else usage(name); + } + + if (argc < 3) usage(name); + + string soname = argv[1]; + string wavname = argv[2]; + string plugid = ""; + string output = ""; + int outputNo = -1; + string outfilename; + + if (argc >= 4) { + + int idx = 3; + + if (isdigit(*argv[idx])) { + outputNo = atoi(argv[idx++]); + } + + if (argc == idx + 2) { + if (!strcmp(argv[idx], "-o")) { + outfilename = argv[idx+1]; + } else usage(name); + } else if (argc != idx) { + (usage(name)); + } + } + + cerr << endl << name << ": Running..." << endl; + + cerr << "Reading file: \"" << wavname << "\", writing to "; + if (outfilename == "") { + cerr << "standard output" << endl; + } else { + cerr << "\"" << outfilename << "\"" << endl; + } + + string::size_type sep = soname.find(':'); + + if (sep != string::npos) { + plugid = soname.substr(sep + 1); + soname = soname.substr(0, sep); + + sep = plugid.find(':'); + if (sep != string::npos) { + output = plugid.substr(sep + 1); + plugid = plugid.substr(0, sep); + } + } + + if (plugid == "") { + usage(name); + } + + if (output != "" && outputNo != -1) { + usage(name); + } + + if (output == "" && outputNo == -1) { + outputNo = 0; + } + + return runPlugin(name, soname, plugid, output, outputNo, + wavname, outfilename); +} + + +int runPlugin(string myname, string soname, string id, + string output, int outputNo, string wavname, + string outfilename) +{ + PluginLoader *loader = PluginLoader::getInstance(); + + PluginLoader::PluginKey key = loader->composePluginKey(soname, id); + + SNDFILE *sndfile; + SF_INFO sfinfo; + memset(&sfinfo, 0, sizeof(SF_INFO)); + + sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo); + if (!sndfile) { + cerr << myname << ": ERROR: Failed to open input file \"" + << wavname << "\": " << sf_strerror(sndfile) << endl; + return 1; + } + + ofstream *out = 0; + if (outfilename != "") { + out = new ofstream(outfilename.c_str(), ios::out); + if (!*out) { + cerr << myname << ": ERROR: Failed to open output file \"" + << outfilename << "\" for writing" << endl; + delete out; + return 1; + } + } + + Vamp::Plugin *plugin = loader->loadPlugin + (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL); + if (!plugin) { + cerr << myname << ": ERROR: Failed to load plugin \"" << id + << "\" from library \"" << soname << "\"" << endl; + sf_close(sndfile); + if (out) { + out->close(); + delete out; + } + return 1; + } + + cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; + + int blockSize = plugin->getPreferredBlockSize(); + int stepSize = plugin->getPreferredStepSize(); + + if (blockSize == 0) blockSize = 1024; + if (stepSize == 0) { + if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) { + stepSize = blockSize/2; + } else { + stepSize = blockSize; + } + } + + int channels = sfinfo.channels; + + float *filebuf = new float[blockSize * channels]; + float **plugbuf = new float*[channels]; + for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2]; + + cerr << "Using block size = " << blockSize << ", step size = " + << stepSize << endl; + + int minch = plugin->getMinChannelCount(); + int maxch = plugin->getMaxChannelCount(); + cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; + cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl; + + Vamp::Plugin::OutputList outputs = plugin->getOutputDescriptors(); + Vamp::Plugin::OutputDescriptor od; + + int returnValue = 1; + int progress = 0; + + if (outputs.empty()) { + cerr << "ERROR: Plugin has no outputs!" << endl; + goto done; + } + + if (outputNo < 0) { + + for (size_t oi = 0; oi < outputs.size(); ++oi) { + if (outputs[oi].identifier == output) { + outputNo = oi; + break; + } + } + + if (outputNo < 0) { + cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl; + goto done; + } + + } else { + + if (int(outputs.size()) <= outputNo) { + cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl; + goto done; + } + } + + od = outputs[outputNo]; + cerr << "Output is: \"" << od.identifier << "\"" << endl; + + if (!plugin->initialise(channels, stepSize, blockSize)) { + cerr << "ERROR: Plugin initialise (channels = " << channels + << ", stepSize = " << stepSize << ", blockSize = " + << blockSize << ") failed." << endl; + goto done; + } + + for (size_t i = 0; i < sfinfo.frames; i += stepSize) { + + int count; + + if (sf_seek(sndfile, i, SEEK_SET) < 0) { + cerr << "ERROR: sf_seek failed: " << sf_strerror(sndfile) << endl; + break; + } + + if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) { + cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; + break; + } + + for (int c = 0; c < channels; ++c) { + int j = 0; + while (j < count) { + plugbuf[c][j] = filebuf[j * sfinfo.channels + c]; + ++j; + } + while (j < blockSize) { + plugbuf[c][j] = 0.0f; + ++j; + } + } + + printFeatures + (i, sfinfo.samplerate, outputNo, plugin->process + (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate)), + out); + + int pp = progress; + progress = lrintf((float(i) / sfinfo.frames) * 100.f); + if (progress != pp && out) { + cerr << "\r" << progress << "%"; + } + } + if (out) cerr << "\rDone" << endl; + + printFeatures(sfinfo.frames, sfinfo.samplerate, outputNo, + plugin->getRemainingFeatures(), out); + + returnValue = 0; + +done: + delete plugin; + if (out) { + out->close(); + delete out; + } + sf_close(sndfile); + return returnValue; +} + +void +printPluginPath(bool verbose) +{ + if (verbose) { + cout << "\nVamp plugin search path: "; + } + + vector<string> path = Vamp::PluginHostAdapter::getPluginPath(); + for (size_t i = 0; i < path.size(); ++i) { + if (verbose) { + cout << "[" << path[i] << "]"; + } else { + cout << path[i] << endl; + } + } + + if (verbose) cout << endl; +} + +void +enumeratePlugins() +{ + PluginLoader *loader = PluginLoader::getInstance(); + + cout << "\nVamp plugin libraries found in search path:" << endl; + + std::vector<PluginLoader::PluginKey> plugins = loader->listPlugins(); + typedef std::multimap<std::string, PluginLoader::PluginKey> + LibraryMap; + LibraryMap libraryMap; + + for (size_t i = 0; i < plugins.size(); ++i) { + std::string path = loader->getLibraryPathForPlugin(plugins[i]); + libraryMap.insert(LibraryMap::value_type(path, plugins[i])); + } + + std::string prevPath = ""; + int index = 0; + + for (LibraryMap::iterator i = libraryMap.begin(); + i != libraryMap.end(); ++i) { + + std::string path = i->first; + PluginLoader::PluginKey key = i->second; + + if (path != prevPath) { + prevPath = path; + index = 0; + cout << "\n " << path << ":" << endl; + } + + Vamp::Plugin *plugin = loader->loadPlugin(key, 48000); + if (plugin) { + + char c = char('A' + index); + if (c > 'Z') c = char('a' + (index - 26)); + + cout << " [" << c << "] [v" + << plugin->getVampApiVersion() << "] " + << plugin->getName() << ", \"" + << plugin->getIdentifier() << "\"" << " [" + << plugin->getMaker() << "]" << endl; + + PluginLoader::PluginCategoryHierarchy category = + loader->getPluginCategory(key); + if (!category.empty()) { + cout << " "; + for (size_t ci = 0; ci < category.size(); ++ci) { + cout << " > " << category[ci]; + } + cout << endl; + } + + if (plugin->getDescription() != "") { + cout << " - " << plugin->getDescription() << endl; + } + + Vamp::Plugin::OutputList outputs = + plugin->getOutputDescriptors(); + + if (outputs.size() > 1) { + for (size_t j = 0; j < outputs.size(); ++j) { + cout << " (" << j << ") " + << outputs[j].name << ", \"" + << outputs[j].identifier << "\"" << endl; + if (outputs[j].description != "") { + cout << " - " + << outputs[j].description << endl; + } + } + } + + ++index; + + delete plugin; + } + } + + cout << endl; +} + +void +printFeatures(int frame, int sr, int output, + Vamp::Plugin::FeatureSet features, ofstream *out) +{ + for (unsigned int i = 0; i < features[output].size(); ++i) { + + Vamp::RealTime rt = Vamp::RealTime::frame2RealTime(frame, sr); + + if (features[output][i].hasTimestamp) { + rt = features[output][i].timestamp; + } + + (out ? *out : cout) << rt.toString() << ":"; + + for (unsigned int j = 0; j < features[output][i].values.size(); ++j) { + (out ? *out : cout) << " " << features[output][i].values[j]; + } + + (out ? *out : cout) << endl; + } +} + + + diff --git a/libs/vamp-sdk/vamp-sdk/Plugin.h b/libs/vamp-sdk/vamp-sdk/Plugin.h new file mode 100644 index 0000000000..159bf4fac6 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/Plugin.h @@ -0,0 +1,405 @@ +/* -*- 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_H_ +#define _VAMP_PLUGIN_H_ + +#include "PluginBase.h" +#include "RealTime.h" + +#include <string> +#include <vector> +#include <map> + +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 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; + }; + + 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, and is + * likely to be disregarded otherwise. + */ + bool hasTimestamp; + + /** + * Timestamp of the output feature. This is mandatory if the + * output has VariableSampleRate, and is likely to be + * disregarded otherwise. Undefined if hasTimestamp is false. + */ + RealTime timestamp; + + /** + * 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; + }; + + 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 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; +}; + +} + +#endif + + + diff --git a/libs/vamp-sdk/vamp-sdk/PluginAdapter.cpp b/libs/vamp-sdk/vamp-sdk/PluginAdapter.cpp new file mode 100644 index 0000000000..1549b4f3aa --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/PluginAdapter.cpp @@ -0,0 +1,851 @@ +/* -*- 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 "PluginAdapter.h" + +//#define DEBUG_PLUGIN_ADAPTER 1 + + +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 cleanup(Plugin *plugin); + void checkOutputMap(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->getVampApiVersion() != VAMP_API_VERSION) { + std::cerr << "Vamp::PluginAdapterBase::Impl::getDescriptor: ERROR: " + << "Plugin object API version " + << plugin->getVampApiVersion() + << " does not match actual API version " + << VAMP_API_VERSION << 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 + + bool result = ((Plugin *)handle)->initialise + (channels, stepSize, blockSize); + 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); +} + +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]); +} + +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 *fs) +{ +#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].label) { + free(list[i].features[j].label); + } + if (list[i].features[j].values) { + free(list[i].features[j].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) +{ + if (m_pluginOutputs.find(plugin) == m_pluginOutputs.end() || + !m_pluginOutputs[plugin]) { + 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; + } +} + +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) { + 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; + + 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]; + + 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]; + + feature->hasTimestamp = fl[j].hasTimestamp; + feature->sec = fl[j].timestamp.sec; + feature->nsec = fl[j].timestamp.nsec; + feature->valueCount = fl[j].values.size(); + + 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; + } + } + + 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 = (VampFeature *)realloc + (m_fs[plugin][n].features, sz * sizeof(VampFeature)); + + while (m_fsizes[plugin][n] < sz) { + m_fs[plugin][n].features[m_fsizes[plugin][n]].valueCount = 0; + m_fs[plugin][n].features[m_fsizes[plugin][n]].values = 0; + m_fs[plugin][n].features[m_fsizes[plugin][n]].label = 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].values = (float *)realloc + (m_fs[plugin][n].features[j].values, sz * sizeof(float)); + + m_fvsizes[plugin][n][j] = sz; +} + +PluginAdapterBase::Impl::AdapterMap * +PluginAdapterBase::Impl::m_adapterMap = 0; + +} + diff --git a/libs/vamp-sdk/vamp-sdk/PluginAdapter.h b/libs/vamp-sdk/vamp-sdk/PluginAdapter.h new file mode 100644 index 0000000000..bfc97508eb --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/PluginAdapter.h @@ -0,0 +1,117 @@ +/* -*- 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 <vamp/vamp.h> + +#include "Plugin.h" + +#include <map> + +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; + } +}; + +} + +#endif + diff --git a/libs/vamp-sdk/vamp-sdk/PluginBase.h b/libs/vamp-sdk/vamp-sdk/PluginBase.h new file mode 100644 index 0000000000..38d2b49904 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/PluginBase.h @@ -0,0 +1,252 @@ +/* -*- 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_BASE_H_ +#define _VAMP_PLUGIN_BASE_H_ + +#include <string> +#include <vector> + +#define VAMP_SDK_VERSION "1.1" + +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 1; } + + /** + * 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; + }; + + 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; +}; + +} + +#endif diff --git a/libs/vamp-sdk/vamp-sdk/PluginHostAdapter.cpp b/libs/vamp-sdk/vamp-sdk/PluginHostAdapter.cpp new file mode 100644 index 0000000000..12e15393fc --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/PluginHostAdapter.cpp @@ -0,0 +1,418 @@ +/* -*- 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 "PluginHostAdapter.h" + +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 = "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) return; + 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) { + 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; + + 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) { + + for (unsigned int j = 0; j < list.featureCount; ++j) { + + Feature feature; + feature.hasTimestamp = list.features[j].hasTimestamp; + feature.timestamp = RealTime(list.features[j].sec, + list.features[j].nsec); + + for (unsigned int k = 0; k < list.features[j].valueCount; ++k) { + feature.values.push_back(list.features[j].values[k]); + } + + if (list.features[j].label) { + feature.label = list.features[j].label; + } + + fs[i].push_back(feature); + } + } + } +} + +} diff --git a/libs/vamp-sdk/vamp-sdk/PluginHostAdapter.h b/libs/vamp-sdk/vamp-sdk/PluginHostAdapter.h new file mode 100644 index 0000000000..80ae6208a4 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/PluginHostAdapter.h @@ -0,0 +1,117 @@ +/* -*- 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 <vamp/vamp.h> +#include <vamp-sdk/Plugin.h> + +#include <vector> + +namespace Vamp { + +/** + * \class PluginHostAdapter PluginHostAdapter.h <vamp-sdk/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; +}; + +} + +#endif + + diff --git a/libs/vamp-sdk/vamp-sdk/RealTime.cpp b/libs/vamp-sdk/vamp-sdk/RealTime.cpp new file mode 100644 index 0000000000..0b541cc33e --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/RealTime.cpp @@ -0,0 +1,254 @@ +/* -*- 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; + +#include "RealTime.h" + +#ifndef _WIN32 +#include <sys/time.h> +#endif + +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); + + // We like integers. The last term is always zero unless the + // sample rate is greater than 1MHz, but hell, you never know... + + long frame = + time.sec * sampleRate + + (time.msec() * sampleRate) / 1000 + + ((time.usec() - 1000 * time.msec()) * sampleRate) / 1000000 + + ((time.nsec - 1000 * time.usec()) * sampleRate) / 1000000000; + + return frame; +} + +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)(((float(frame) * 1000000) / long(sampleRate)) * 1000); + return rt; +} + +const RealTime RealTime::zeroTime(0,0); + +} diff --git a/libs/vamp-sdk/vamp-sdk/RealTime.h b/libs/vamp-sdk/vamp-sdk/RealTime.h new file mode 100644 index 0000000000..4dd78fd209 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/RealTime.h @@ -0,0 +1,154 @@ +/* -*- 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 + +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; + + // Find the fractional difference between 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; + + // Convenience functions for handling sample frames + // + static long realTime2Frame(const RealTime &r, unsigned int sampleRate); + static RealTime frame2RealTime(long frame, unsigned int sampleRate); + + static const RealTime zeroTime; +}; + +std::ostream &operator<<(std::ostream &out, const RealTime &rt); + +} + +#endif diff --git a/libs/vamp-sdk/vamp-sdk/doc-overview b/libs/vamp-sdk/vamp-sdk/doc-overview new file mode 100644 index 0000000000..4beb6981a2 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/doc-overview @@ -0,0 +1,120 @@ + +/** \mainpage Vamp Plugin SDK + +\section about About Vamp + +Vamp is an API for C and C++ plugins that process sampled audio data +to produce descriptive output (measurements or semantic observations). +Find more information at http://www.vamp-plugins.org/ . + +Although the official API for Vamp plugins is defined in C for maximum +binary compatibility, we strongly recommend using the provided C++ +classes in the SDK to implement your own plugins and hosts. + +\section plugins For Plugins + +Plugins should subclass Vamp::Plugin, and then use a +Vamp::PluginAdapter to expose the correct C API for the plugin. Read +the documentation for Vamp::PluginBase and Vamp::Plugin before +starting. + +Plugins should be compiled and linked into dynamic libraries using the +usual convention for your platform, and should link (preferably +statically) with -lvamp-sdk. Any number of plugins can reside in a +single dynamic library. See plugins.cpp in the example plugins +directory for the sort of code that will need to accompany your plugin +class or classes, to make it possible for a host to look up your +plugins properly. + +The following example plugins are provided: + + - 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 is an implementation of SuperCollider's + amplitude-follower algorithm as a simple Vamp plugin. + + - 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. + +\section hosts For Hosts + +Hosts will normally use a Vamp::PluginHostAdapter to convert each +plugin's exposed C API back into a useful Vamp::Plugin C++ object. + +Starting with version 1.1 of the Vamp SDK, there are several classes +in the Vamp::HostExt namespace that aim to make the host's life as +easy as possible: + + - Vamp::HostExt::PluginLoader provides a very simple 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 simple means for + hosts to handle plugins that expect frequency-domain input, without + having to convert the input themselves. + + - Vamp::HostExt::PluginChannelAdapter provides a simple means for + hosts to use plugins that do not necessarily support the same number + of audio channels as they have available, without having to apply 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. + +Hosts should link with -lvamp-hostsdk. + +(The following notes in this section are mostly relevant for +developers that are not using the HostExt classes, or that wish to +know more about the policy they implement.) + +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. + +Our suggestion for a host is to search each directory in this path 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. The example host has some code that may help, but 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 + +\code +vamp:pluginlibrary:pluginname::General Category > Specific Category +\endcode + +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 API itself. + +There is an example host in the "host" directory from which code may +be drawn. + +\section license License + +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. + + +*/ diff --git a/libs/vamp-sdk/vamp-sdk/hostext/PluginChannelAdapter.cpp b/libs/vamp-sdk/vamp-sdk/hostext/PluginChannelAdapter.cpp new file mode 100644 index 0000000000..3ce51cedd2 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/hostext/PluginChannelAdapter.cpp @@ -0,0 +1,228 @@ +/* -*- 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-2007 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 "PluginChannelAdapter.h" + +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); + +protected: + Plugin *m_plugin; + size_t m_blockSize; + size_t m_inputChannels; + size_t m_pluginChannels; + float **m_buffer; + 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::Impl::Impl(Plugin *plugin) : + m_plugin(plugin), + m_blockSize(0), + m_inputChannels(0), + m_pluginChannels(0), + m_buffer(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_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::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); + } +} + +} + +} + + diff --git a/libs/vamp-sdk/vamp-sdk/hostext/PluginChannelAdapter.h b/libs/vamp-sdk/vamp-sdk/hostext/PluginChannelAdapter.h new file mode 100644 index 0000000000..a2b4d89aee --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/hostext/PluginChannelAdapter.h @@ -0,0 +1,128 @@ +/* -*- 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-2007 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 "PluginWrapper.h" + +namespace Vamp { + +namespace HostExt { + +/** + * \class PluginChannelAdapter PluginChannelAdapter.h <vamp-sdk/hostext/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: + PluginChannelAdapter(Plugin *plugin); // I take ownership of plugin + virtual ~PluginChannelAdapter(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + +protected: + class Impl; + Impl *m_impl; +}; + +} + +} + +#endif diff --git a/libs/vamp-sdk/vamp-sdk/hostext/PluginInputDomainAdapter.cpp b/libs/vamp-sdk/vamp-sdk/hostext/PluginInputDomainAdapter.cpp new file mode 100644 index 0000000000..3fc0d74720 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/hostext/PluginInputDomainAdapter.cpp @@ -0,0 +1,458 @@ +/* -*- 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-2007 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 "PluginInputDomainAdapter.h" + +#include <cmath> + +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); + + size_t getPreferredStepSize() const; + size_t getPreferredBlockSize() const; + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + +protected: + Plugin *m_plugin; + float m_inputSampleRate; + size_t m_channels; + size_t m_blockSize; + float **m_freqbuf; + double *m_ri; + double *m_ro; + double *m_io; + + void fft(unsigned int n, bool inverse, + double *ri, double *ii, double *ro, double *io); + + 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); +} + +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); +} + + PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : + m_plugin(plugin), + m_inputSampleRate(inputSampleRate), + m_channels(0), + m_blockSize(0), + m_freqbuf(0) +{ +} + +PluginInputDomainAdapter::Impl::~Impl() +{ + // the adapter will delete the plugin + + if (m_channels > 0) { + for (size_t c = 0; c < m_channels; ++c) { + delete[] m_freqbuf[c]; + } + delete[] m_freqbuf; + delete[] m_ri; + delete[] m_ro; + delete[] m_io; + } +} + +bool +PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (m_plugin->getInputDomain() == TimeDomain) { + + m_blockSize = blockSize; + m_channels = channels; + + return m_plugin->initialise(channels, stepSize, blockSize); + } + + if (blockSize < 2) { + std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not supported" << std::endl; + return false; + } + + if (blockSize & (blockSize-1)) { + std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl; + return false; + } + + if (m_channels > 0) { + for (size_t c = 0; c < m_channels; ++c) { + delete[] m_freqbuf[c]; + } + delete[] m_freqbuf; + delete[] m_ri; + delete[] m_ro; + delete[] m_io; + } + + m_blockSize = blockSize; + m_channels = channels; + + m_freqbuf = new float *[m_channels]; + for (size_t c = 0; c < m_channels; ++c) { + m_freqbuf[c] = new float[m_blockSize + 2]; + } + m_ri = new double[m_blockSize]; + m_ro = new double[m_blockSize]; + m_io = new double[m_blockSize]; + + return m_plugin->initialise(channels, stepSize, blockSize); +} + +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: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: blocksize < 2 not" << std::endl + << "supported, increasing from " << blockSize << " to 2" << std::endl; + blockSize = 2; + + } else if (blockSize & (blockSize-1)) { + + // not a power of two, can't handle that with our current 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: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl; + blockSize = nearest; + } + + return blockSize; +} + +// for some visual studii apparently +#ifndef M_PI +#define M_PI 3.14159265358979232846 +#endif + +Plugin::FeatureSet +PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers, + RealTime timestamp) +{ + if (m_plugin->getInputDomain() == TimeDomain) { + return m_plugin->process(inputBuffers, timestamp); + } + + // The timestamp supplied should be (according to the Vamp::Plugin + // spec) the time of the start of the time-domain input block. + // However, we want to pass to the plugin an FFT output calculated + // from the block of samples _centred_ on that timestamp. + // + // We have two options: + // + // 1. Buffer the input, calculating the fft of the values at the + // passed-in block minus blockSize/2 rather than starting at the + // passed-in block. So each time we call process on the plugin, + // we are passing in the same timestamp as was passed to our own + // process plugin, but not (the frequency domain representation + // of) the same set of samples. Advantages: avoids confusion in + // the host by ensuring the returned values have timestamps + // comparable with that passed in to this function (in fact this + // is pretty much essential for one-value-per-block outputs); + // consistent with hosts such as SV that deal with the + // frequency-domain transform themselves. Disadvantages: means + // making the not necessarily correct assumption that the samples + // preceding the first official block are all zero (or some other + // known value). + // + // 2. Increase the passed-in timestamps by half the blocksize. So + // when we call process, we are passing in the frequency domain + // representation of the same set of samples as passed to us, but + // with a different timestamp. Advantages: simplicity; avoids + // iffy assumption mentioned above. Disadvantages: inconsistency + // with SV in cases where stepSize != blockSize/2; potential + // confusion arising from returned timestamps being calculated + // from the adjusted input timestamps rather than the original + // ones (and inaccuracy where the returned timestamp is implied, + // as in one-value-per-block). + // + // Neither way is ideal, but I don't think either is strictly + // incorrect either. I think this is just a case where the same + // plugin can legitimately produce differing results from the same + // input data, depending on how that data is packaged. + // + // We'll go for option 2, adjusting the timestamps. Note in + // particular that this means some results can differ from those + // produced by SV. + +// std::cerr << "PluginInputDomainAdapter: sampleRate " << m_inputSampleRate << ", blocksize " << m_blockSize << ", adjusting time from " << timestamp; + + timestamp = timestamp + RealTime::frame2RealTime + (m_blockSize/2, int(m_inputSampleRate + 0.5)); + +// std::cerr << " to " << timestamp << std::endl; + + for (size_t c = 0; c < m_channels; ++c) { + + for (size_t i = 0; i < m_blockSize; ++i) { + // Hanning window + m_ri[i] = double(inputBuffers[c][i]) + * (0.50 - 0.50 * cos((2 * M_PI * i) + / m_blockSize)); + } + + for (size_t 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; + } + + fft(m_blockSize, false, m_ri, 0, m_ro, m_io); + + for (size_t i = 0; i <= m_blockSize/2; ++i) { + m_freqbuf[c][i * 2] = m_ro[i]; + m_freqbuf[c][i * 2 + 1] = m_io[i]; + } + } + + return m_plugin->process(m_freqbuf, timestamp); +} + +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; + } + } +} + +} + +} + diff --git a/libs/vamp-sdk/vamp-sdk/hostext/PluginInputDomainAdapter.h b/libs/vamp-sdk/vamp-sdk/hostext/PluginInputDomainAdapter.h new file mode 100644 index 0000000000..73da053149 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/hostext/PluginInputDomainAdapter.h @@ -0,0 +1,103 @@ +/* -*- 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-2007 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 "PluginWrapper.h" + +namespace Vamp { + +namespace HostExt { + +/** + * \class PluginInputDomainAdapter PluginInputDomainAdapter.h <vamp-sdk/hostext/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: + PluginInputDomainAdapter(Plugin *plugin); // I take ownership of plugin + virtual ~PluginInputDomainAdapter(); + + bool initialise(size_t channels, size_t stepSize, size_t blockSize); + + InputDomain getInputDomain() const; + + size_t getPreferredStepSize() const; + size_t getPreferredBlockSize() const; + + FeatureSet process(const float *const *inputBuffers, RealTime timestamp); + +protected: + class Impl; + Impl *m_impl; +}; + +} + +} + +#endif diff --git a/libs/vamp-sdk/vamp-sdk/hostext/PluginLoader.cpp b/libs/vamp-sdk/vamp-sdk/hostext/PluginLoader.cpp new file mode 100644 index 0000000000..cb71fc4750 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/hostext/PluginLoader.cpp @@ -0,0 +1,601 @@ +/* -*- 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-2007 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-sdk/PluginHostAdapter.h" +#include "PluginLoader.h" +#include "PluginInputDomainAdapter.h" +#include "PluginChannelAdapter.h" + +#include <fstream> +#include <cctype> // tolower + +#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; + +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); + +protected: + class PluginDeletionNotifyAdapter : public PluginWrapper { + public: + PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader); + virtual ~PluginDeletionNotifyAdapter(); + protected: + Impl *m_loader; + }; + + 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); +}; + +PluginLoader * +PluginLoader::m_instance = 0; + +PluginLoader::PluginLoader() +{ + m_impl = new Impl(); +} + +PluginLoader::~PluginLoader() +{ + delete m_impl; +} + +PluginLoader * +PluginLoader::getInstance() +{ + if (!m_instance) m_instance = new PluginLoader(); + 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() +{ +} + +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) { + unloadLibrary(handle); + continue; + } + + int index = 0; + const VampPluginDescriptor *descriptor = 0; + + while ((descriptor = fn(VAMP_API_VERSION, index))) { + ++index; + if (identifier != "") { + if (descriptor->identifier != identifier) continue; + } + PluginKey key = composePluginKey(*fi, descriptor->identifier); +// std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl; + if (m_pluginLibraryNameMap.find(key) == + m_pluginLibraryNameMap.end()) { + m_pluginLibraryNameMap[key] = fullPath; + } + } + + 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 == "") return 0; + + void *handle = loadLibrary(fullPath); + if (!handle) return 0; + + VampGetPluginDescriptorFunction fn = + (VampGetPluginDescriptorFunction)lookupInLibrary + (handle, "vampGetPluginDescriptor"); + + if (!fn) { + 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_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 + handle = LoadLibrary(path.c_str()); + if (!handle) { + cerr << "Vamp::HostExt::PluginLoader: Unable to load library \"" + << path << "\"" << endl; + } +#else + handle = dlopen(path.c_str(), RTLD_LAZY); + 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; + 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); + +#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_type & DT_REG) || !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); +} + +} + +} diff --git a/libs/vamp-sdk/vamp-sdk/hostext/PluginLoader.h b/libs/vamp-sdk/vamp-sdk/hostext/PluginLoader.h new file mode 100644 index 0000000000..82ae22b930 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/hostext/PluginLoader.h @@ -0,0 +1,218 @@ +/* -*- 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-2007 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 "PluginWrapper.h" + +namespace Vamp { + +class Plugin; + +namespace HostExt { + +/** + * \class PluginLoader PluginLoader.h <vamp-sdk/hostext/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_ALL - Perform all available adaptations, where meaningful. + * + * See PluginInputDomainAdapter and PluginChannelAdapter 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_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; +}; + +} + +} + +#endif + diff --git a/libs/vamp-sdk/vamp-sdk/hostext/PluginWrapper.cpp b/libs/vamp-sdk/vamp-sdk/hostext/PluginWrapper.cpp new file mode 100644 index 0000000000..dcbdf5b73a --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/hostext/PluginWrapper.cpp @@ -0,0 +1,201 @@ +/* -*- 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-2007 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 "PluginWrapper.h" + +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(); +} + +} + +} + diff --git a/libs/vamp-sdk/vamp-sdk/hostext/PluginWrapper.h b/libs/vamp-sdk/vamp-sdk/hostext/PluginWrapper.h new file mode 100644 index 0000000000..d5ec1da0e8 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/hostext/PluginWrapper.h @@ -0,0 +1,106 @@ +/* -*- 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-2007 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 <vamp-sdk/Plugin.h> + +namespace Vamp { + +namespace HostExt { + +/** + * \class PluginWrapper PluginWrapper.h <vamp-sdk/hostext/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(); + +protected: + PluginWrapper(Plugin *plugin); // I take ownership of plugin + Plugin *m_plugin; +}; + +} + +} + +#endif diff --git a/libs/vamp-sdk/vamp-sdk/libvamp-hostsdk.la.in b/libs/vamp-sdk/vamp-sdk/libvamp-hostsdk.la.in new file mode 100644 index 0000000000..83362dc39c --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/libvamp-hostsdk.la.in @@ -0,0 +1,9 @@ +dlname='%LINK_ABI%' +library_names='%LIBNAME% %LINK_ABI% %LINK_DEV%' +old_library='%STATIC%' +dependency_libs='' +current=2 +age=0 +revision=0 +installed=yes +libdir='%LIBS%' diff --git a/libs/vamp-sdk/vamp-sdk/libvamp-sdk.la.in b/libs/vamp-sdk/vamp-sdk/libvamp-sdk.la.in new file mode 100644 index 0000000000..1674afe3e4 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/libvamp-sdk.la.in @@ -0,0 +1,9 @@ +dlname='%LINK_ABI%' +library_names='%LIBNAME% %LINK_ABI% %LINK_DEV%' +old_library='%STATIC%' +dependency_libs='' +current=1 +age=1 +revision=0 +installed=yes +libdir='%LIBS%' diff --git a/libs/vamp-sdk/vamp-sdk/vamp-hostsdk.pc.in b/libs/vamp-sdk/vamp-sdk/vamp-hostsdk.pc.in new file mode 100644 index 0000000000..d5432c0540 --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/vamp-hostsdk.pc.in @@ -0,0 +1,10 @@ +prefix=%PREFIX% +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: vamp-hostsdk +Version: 1.1.0 +Description: Development library for Vamp audio analysis plugin hosts +Libs: -L${libdir} -lvamp-hostsdk +Cflags: -I${includedir} diff --git a/libs/vamp-sdk/vamp-sdk/vamp-sdk.pc.in b/libs/vamp-sdk/vamp-sdk/vamp-sdk.pc.in new file mode 100644 index 0000000000..22cea32bca --- /dev/null +++ b/libs/vamp-sdk/vamp-sdk/vamp-sdk.pc.in @@ -0,0 +1,10 @@ +prefix=%PREFIX% +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: vamp-sdk +Version: 1.1.0 +Description: Development library for Vamp audio analysis plugins +Libs: -L${libdir} -lvamp-sdk +Cflags: -I${includedir} diff --git a/libs/vamp-sdk/vamp/vamp.h b/libs/vamp-sdk/vamp/vamp.h new file mode 100644 index 0000000000..4f0145ab59 --- /dev/null +++ b/libs/vamp-sdk/vamp/vamp.h @@ -0,0 +1,339 @@ +/* -*- 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 1 + +/** + * 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; + +} 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 _VampFeatureList +{ + /** Number of features in this feature list. */ + unsigned int featureCount; + + /** Features in this feature list. May be NULL if featureCount is zero. */ + VampFeature *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. +*/ +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 diff --git a/libs/vamp-sdk/vamp/vamp.pc.in b/libs/vamp-sdk/vamp/vamp.pc.in new file mode 100644 index 0000000000..82d4decd34 --- /dev/null +++ b/libs/vamp-sdk/vamp/vamp.pc.in @@ -0,0 +1,10 @@ +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} |