Mercurial > hg > vamp-onsetsds-plugin
changeset 3:73972910a2de
Replace onsetsds subdirectory with a subrepository
author | Chris Cannam |
---|---|
date | Mon, 09 Jul 2012 14:17:16 +0100 |
parents | 6414d166d4d8 |
children | 8fde2f42b6a0 |
files | .hgsub .hgsubstate onsetsds/AUTHORS onsetsds/COPYING onsetsds/ChangeLog onsetsds/README onsetsds/doc/Doxyfile onsetsds/doc/footer.html onsetsds/doc/mainpage.dox onsetsds/onsetsds.c onsetsds/onsetsds.h onsetsds/onsetsdshelpers.c onsetsds/onsetsdshelpers.h |
diffstat | 13 files changed, 2 insertions(+), 1905 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgsub Mon Jul 09 14:17:16 2012 +0100 @@ -0,0 +1,1 @@ +onsetsds = https://onsetsds.svn.sourceforge.net/svnroot/onsetsds
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgsubstate Mon Jul 09 14:17:16 2012 +0100 @@ -0,0 +1,1 @@ +0000000000000000000000000000000000000000 onsetsds
--- a/onsetsds/AUTHORS Wed Jul 09 12:56:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - -Dan Stowell, dan.stowell@elec.qmul.ac.uk \ No newline at end of file
--- a/onsetsds/COPYING Wed Jul 09 12:56:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License.
--- a/onsetsds/ChangeLog Wed Jul 09 12:56:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -2007-11 Dan Stowell - * Significant refactoring from v0.1, which was a set of SuperCollider UGens. - * VERSION: 0.2.0
--- a/onsetsds/README Wed Jul 09 12:56:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ - - ---------------------------------------------------------- - OnsetsDS - - Musical onset detection library - (c) 2007 Dan Stowell - Made available under the GPL v2 - see COPYING for details. - ---------------------------------------------------------- - - - -USAGE - -If your system can provide frequency-domain data (e.g. by performing FFT on the -input audio), then to perform onset detection you only need onsetsds.h and -onsetsds.c. These need no additional libraries beyond the standard C libraries. - -If you aren't already doing the FFT then you can also use onsetsdshelpers.c -and onsetsdshelpers.h, which can process raw audio, from a buffer or from a -file. These require two additional libraries: - - * libsndfile - I used version 1.0.17 - http://www.meganerd.com/libsndfile - - * FFTW 3 (floating-point version) - I used version 3.1.2 - http://www.fftw.org - -See the HTML documentation for a worked example. -
--- a/onsetsds/doc/Doxyfile Wed Jul 09 12:56:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ -# Doxyfile 1.5.3 - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- -DOXYFILE_ENCODING = UTF-8 -PROJECT_NAME = OnsetsDS -PROJECT_NUMBER = v0.2 -OUTPUT_DIRECTORY = . -CREATE_SUBDIRS = NO -OUTPUT_LANGUAGE = English -BRIEF_MEMBER_DESC = YES -REPEAT_BRIEF = YES -ABBREVIATE_BRIEF = "The $name class " \ - "The $name widget " \ - "The $name file " \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the -ALWAYS_DETAILED_SEC = NO -INLINE_INHERITED_MEMB = NO -FULL_PATH_NAMES = NO -STRIP_FROM_PATH = /Applications/ -STRIP_FROM_INC_PATH = -SHORT_NAMES = NO -JAVADOC_AUTOBRIEF = NO -QT_AUTOBRIEF = NO -MULTILINE_CPP_IS_BRIEF = NO -DETAILS_AT_TOP = NO -INHERIT_DOCS = YES -SEPARATE_MEMBER_PAGES = NO -TAB_SIZE = 8 -ALIASES = -OPTIMIZE_OUTPUT_FOR_C = YES -OPTIMIZE_OUTPUT_JAVA = NO -BUILTIN_STL_SUPPORT = NO -CPP_CLI_SUPPORT = NO -DISTRIBUTE_GROUP_DOC = NO -SUBGROUPING = YES -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- -EXTRACT_ALL = YES -EXTRACT_PRIVATE = YES -EXTRACT_STATIC = YES -EXTRACT_LOCAL_CLASSES = YES -EXTRACT_LOCAL_METHODS = NO -EXTRACT_ANON_NSPACES = NO -HIDE_UNDOC_MEMBERS = NO -HIDE_UNDOC_CLASSES = NO -HIDE_FRIEND_COMPOUNDS = NO -HIDE_IN_BODY_DOCS = NO -INTERNAL_DOCS = NO -CASE_SENSE_NAMES = NO -HIDE_SCOPE_NAMES = NO -SHOW_INCLUDE_FILES = YES -INLINE_INFO = YES -SORT_MEMBER_DOCS = NO -SORT_BRIEF_DOCS = NO -SORT_BY_SCOPE_NAME = NO -GENERATE_TODOLIST = NO -GENERATE_TESTLIST = NO -GENERATE_BUGLIST = NO -GENERATE_DEPRECATEDLIST= NO -ENABLED_SECTIONS = -MAX_INITIALIZER_LINES = 30 -SHOW_USED_FILES = YES -SHOW_DIRECTORIES = NO -FILE_VERSION_FILTER = -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- -QUIET = NO -WARNINGS = YES -WARN_IF_UNDOCUMENTED = YES -WARN_IF_DOC_ERROR = YES -WARN_NO_PARAMDOC = NO -WARN_FORMAT = "$file:$line: $text " -WARN_LOGFILE = -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- -INPUT = .. -INPUT_ENCODING = UTF-8 -FILE_PATTERNS = *.c \ - *.cc \ - *.cxx \ - *.cpp \ - *.c++ \ - *.d \ - *.java \ - *.ii \ - *.ixx \ - *.ipp \ - *.i++ \ - *.inl \ - *.h \ - *.hh \ - *.hxx \ - *.hpp \ - *.h++ \ - *.idl \ - *.odl \ - *.cs \ - *.php \ - *.php3 \ - *.inc \ - *.m \ - *.mm \ - *.dox \ - *.py -RECURSIVE = YES -EXCLUDE = -EXCLUDE_SYMLINKS = NO -EXCLUDE_PATTERNS = */.svn* */doc/html* -EXCLUDE_SYMBOLS = -EXAMPLE_PATH = -EXAMPLE_PATTERNS = * -EXAMPLE_RECURSIVE = NO -IMAGE_PATH = -INPUT_FILTER = -FILTER_PATTERNS = -FILTER_SOURCE_FILES = NO -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- -SOURCE_BROWSER = NO -INLINE_SOURCES = NO -STRIP_CODE_COMMENTS = YES -REFERENCED_BY_RELATION = NO -REFERENCES_RELATION = NO -REFERENCES_LINK_SOURCE = YES -USE_HTAGS = NO -VERBATIM_HEADERS = NO -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- -ALPHABETICAL_INDEX = NO -COLS_IN_ALPHA_INDEX = 5 -IGNORE_PREFIX = -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- -GENERATE_HTML = YES -HTML_OUTPUT = html -HTML_FILE_EXTENSION = .html -HTML_HEADER = -HTML_FOOTER = footer.html -HTML_STYLESHEET = -HTML_ALIGN_MEMBERS = YES -GENERATE_HTMLHELP = NO -HTML_DYNAMIC_SECTIONS = NO -CHM_FILE = -HHC_LOCATION = -GENERATE_CHI = NO -BINARY_TOC = NO -TOC_EXPAND = NO -DISABLE_INDEX = NO -ENUM_VALUES_PER_LINE = 4 -GENERATE_TREEVIEW = NO -TREEVIEW_WIDTH = 250 -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- -GENERATE_LATEX = NO -LATEX_OUTPUT = latex -LATEX_CMD_NAME = latex -MAKEINDEX_CMD_NAME = makeindex -COMPACT_LATEX = NO -PAPER_TYPE = a4wide -EXTRA_PACKAGES = -LATEX_HEADER = -PDF_HYPERLINKS = NO -USE_PDFLATEX = NO -LATEX_BATCHMODE = NO -LATEX_HIDE_INDICES = NO -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- -GENERATE_RTF = NO -RTF_OUTPUT = rtf -COMPACT_RTF = NO -RTF_HYPERLINKS = NO -RTF_STYLESHEET_FILE = -RTF_EXTENSIONS_FILE = -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- -GENERATE_MAN = NO -MAN_OUTPUT = man -MAN_EXTENSION = .3 -MAN_LINKS = NO -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- -GENERATE_XML = NO -XML_OUTPUT = xml -XML_SCHEMA = -XML_DTD = -XML_PROGRAMLISTING = YES -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- -GENERATE_AUTOGEN_DEF = NO -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- -GENERATE_PERLMOD = NO -PERLMOD_LATEX = NO -PERLMOD_PRETTY = YES -PERLMOD_MAKEVAR_PREFIX = -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- -ENABLE_PREPROCESSING = YES -MACRO_EXPANSION = NO -EXPAND_ONLY_PREDEF = NO -SEARCH_INCLUDES = YES -INCLUDE_PATH = -INCLUDE_FILE_PATTERNS = -PREDEFINED = -EXPAND_AS_DEFINED = -SKIP_FUNCTION_MACROS = YES -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- -TAGFILES = -GENERATE_TAGFILE = -ALLEXTERNALS = NO -EXTERNAL_GROUPS = YES -PERL_PATH = /usr/bin/perl -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- -CLASS_DIAGRAMS = NO -MSCGEN_PATH = /Applications/Doxygen.app/Contents/Resources/ -HIDE_UNDOC_RELATIONS = YES -HAVE_DOT = YES -CLASS_GRAPH = YES -COLLABORATION_GRAPH = YES -GROUP_GRAPHS = YES -UML_LOOK = NO -TEMPLATE_RELATIONS = NO -INCLUDE_GRAPH = NO -INCLUDED_BY_GRAPH = NO -CALL_GRAPH = NO -CALLER_GRAPH = NO -GRAPHICAL_HIERARCHY = YES -DIRECTORY_GRAPH = YES -DOT_IMAGE_FORMAT = png -DOT_PATH = /Applications/Doxygen.app/Contents/Resources/ -DOTFILE_DIRS = -DOT_GRAPH_MAX_NODES = 50 -MAX_DOT_GRAPH_DEPTH = 1000 -DOT_TRANSPARENT = NO -DOT_MULTI_TARGETS = NO -GENERATE_LEGEND = YES -DOT_CLEANUP = YES -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- -SEARCHENGINE = NO
--- a/onsetsds/doc/footer.html Wed Jul 09 12:56:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -</body></html> \ No newline at end of file
--- a/onsetsds/doc/mainpage.dox Wed Jul 09 12:56:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/** \mainpage OnsetsDS - real time musical onset detection C/C++ library - -<small>Copyright (c) 2007 Dan Stowell (Published under the GNU Public License v2). -http://onsetsds.sourceforge.net/</small> - -<h2>Introduction</h2> - -The purpose of %OnsetsDS is to provide capabilities for FFT-based onset -detection that works very efficiently in real-time, and can detect onsets -pretty well in a broad variety of musical signals, with a fast reaction -time. - -It is not specialised for any particular type of signal. Nor is it -particularly tailored towards non-real-time use (if we were working in -non-real-time there are extra things we could do to improve the precision). -Its efficiency and fast reaction are designed with general real-time musical -applications in mind. - -<h2>Download</h2> - -<ul> - <li><a href="http://sourceforge.net/">Download the sourcecode bundle</a></li> - <li>Or access the current development version using subversion [<small><a href="http://sourceforge.net/svn/?group_id=54622" title="What is subversion, and how to use it">info</a></small>]: <br /> - <tt>svn co %https://onsetsds.svn.sourceforge.net/svnroot/onsetsds onsetsds</tt></li> -</ul> - -<h2>Typical usage</h2> - -\code - -// This example uses the recommended settings of an FFT size of 512 (@44.1kHz), -// and a median span of 11. It also uses the "rectified complex deviation" -// onset detection function - your choice of function may be down to taste, -// or to performance on the particular type of sound you're using. - -#include "onsetsds.h" - -// An instance of the OnsetsDS struct, declared/allocated somewhere in your code, -// however you want to do it. -OnsetsDS ods; - - -///////// (1) INITIALISATION: ///////// - -// Allocate contiguous memory using malloc or whatever is reasonable. -float* odsdata = (float*) malloc( onsetsds_memneeded(odftype, 512, 11) ); - -// There are various types of onset detector available, we must choose one -odftype = ODS_ODF_RCOMPLEX; - -// Now initialise the OnsetsDS struct and its associated memory -onsetsds_init(ods, odsdata, ODS_FFT_FFTW3_HC, odftype, 512, 11); - - -///////// (2) EXECUTION: ///////// - -bool onset; -while(running){ - // Grab your 512-point, 50%-overlap, nicely-windowed FFT data, into "fftdata" - - // Then detect. "onset" will be true when there's an onset, false otherwise - onset = onsetsds_process(ods, fftdata); -} - - -///////// (3) TIDYING UP: ///////// - -free(ods->data); // Or free(odsdata), they point to the same thing in this case - -\endcode - -<h2>Research background</h2> - -%OnsetsDS is based on research into musical onset detection -carried out by Dan Stowell, with Dr Mark Plumbley, at -Queen Mary University of London's -<a href="http://www.elec.qmul.ac.uk/digitalmusic/">Centre for Digital Music</a>. - -Relevant publications: - -\li D. Stowell and M. D. Plumbley. -<a href="http://www.elec.qmul.ac.uk/digitalmusic/papers/2007/StowellPlumbley07-icmc.pdf"> -Adaptive whitening for improved real-time audio onset detection.</a> -To appear in: -Proceedings of the International Computer Music Conference (ICMC'07), -Copenhagen, Denmark, August 2007. - -The research stands on the shoulders of other onset detection research, and uses -some concepts from that research - see the ICMC'07 paper and its bibliography -for more details. - - -*/ \ No newline at end of file
--- a/onsetsds/onsetsds.c Wed Jul 09 12:56:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,547 +0,0 @@ -/* - OnsetsDS - real time musical onset detection library. - Copyright (c) 2007 Dan Stowell. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - - -#include "onsetsds.h" - - -#define ODS_DEBUG_POST_CSV 0 - -// Inline -inline float onsetsds_phase_rewrap(float phase); -inline float onsetsds_phase_rewrap(float phase){ - return (phase>MINUSPI && phase<PI) ? phase : phase + TWOPI * (1.f + floorf((MINUSPI - phase) * INV_TWOPI)); -} - - -size_t onsetsds_memneeded (int odftype, size_t fftsize, unsigned int medspan){ - - /* - Need memory for: - - median calculation (2 * medspan floats) - - storing old values (whether as OdsPolarBuf or as weirder float lists) - - storing the OdsPolarBuf (size is NOT sizeof(OdsPolarBuf) but is fftsize) - - storing the PSP (numbins + 2 values) - All these are floats. - */ - - int numbins = (fftsize >> 1) - 1; // No of bins, not counting DC/nyq - - switch(odftype){ - case ODS_ODF_POWER: - case ODS_ODF_MAGSUM: - - // No old FFT frames needed, easy: - return (medspan+medspan + fftsize + numbins + 2) * sizeof(float); - - case ODS_ODF_COMPLEX: - case ODS_ODF_RCOMPLEX: - - return (medspan+medspan + fftsize + numbins + 2 - // For each bin (NOT dc/nyq) we store mag, phase and d_phase - + numbins + numbins + numbins - ) * sizeof(float); - - case ODS_ODF_PHASE: - case ODS_ODF_WPHASE: - - return (medspan+medspan + fftsize + numbins + 2 - // For each bin (NOT dc/nyq) we store phase and d_phase - + numbins + numbins - ) * sizeof(float); - - case ODS_ODF_MKL: - - return (medspan+medspan + fftsize + numbins + 2 - // For each bin (NOT dc/nyq) we store mag - + numbins - ) * sizeof(float); - - - break; - - } - return -1; //bleh -} - - -void onsetsds_init(OnsetsDS *ods, float *odsdata, int fftformat, - int odftype, size_t fftsize, unsigned int medspan, float srate){ - - // The main pointer to the processing area - other pointers will indicate areas within this - ods->data = odsdata; - // Set all vals in processing area to zero - memset(odsdata, 0, onsetsds_memneeded(odftype, fftsize, medspan)); - - ods->srate = srate; - - int numbins = (fftsize >> 1) - 1; // No of bins, not counting DC/nyq - int realnumbins = numbins + 2; - - // Also point the other pointers to the right places - ods->curr = (OdsPolarBuf*) odsdata; - ods->psp = odsdata + fftsize; - ods->odfvals = odsdata + fftsize + realnumbins; - ods->sortbuf = odsdata + fftsize + realnumbins + medspan; - ods->other = odsdata + fftsize + realnumbins + medspan + medspan; - - // Default settings for Adaptive Whitening, user can set own values after init - onsetsds_setrelax(ods, 1.f, fftsize>>1); - ods->floor = 0.1; - - switch(odftype){ - case ODS_ODF_POWER: - ods->odfparam = 0.01; // "powthresh" in SC code - ods->normfactor = 2560.f / (realnumbins * fftsize); - break; - case ODS_ODF_MAGSUM: - ods->odfparam = 0.01; // "powthresh" in SC code - ods->normfactor = 113.137085f / (realnumbins * sqrt(fftsize)); - break; - case ODS_ODF_COMPLEX: - ods->odfparam = 0.01; // "powthresh" in SC code - ods->normfactor = 231.70475f / pow(fftsize, 1.5);// / fftsize; - break; - case ODS_ODF_RCOMPLEX: - ods->odfparam = 0.01; // "powthresh" in SC code - ods->normfactor = 231.70475f / pow(fftsize, 1.5);// / fftsize; - break; - case ODS_ODF_PHASE: - ods->odfparam = 0.01; // "powthresh" in SC code - ods->normfactor = 5.12f / fftsize;// / fftsize; - break; - case ODS_ODF_WPHASE: - ods->odfparam = 0.0001; // "powthresh" in SC code. For WPHASE it's kind of superfluous. - ods->normfactor = 115.852375f / pow(fftsize, 1.5);// / fftsize; - break; - case ODS_ODF_MKL: - ods->odfparam = 0.01; // EPSILON parameter. Brossier recommends 1e-6 but I (ICMC 2007) found larger vals (e.g 0.01) to work better - ods->normfactor = 7.68f * 0.25f / fftsize; - break; - default: - printf("onsetsds_init ERROR: \"odftype\" is not a recognised value\n"); - } - - ods->odfvalpost = 0.f; - ods->odfvalpostprev = 0.f; - ods->thresh = 0.5f; - ods->logmags = false; - - ods->odftype = odftype; - ods->whtype = ODS_WH_ADAPT_MAX1; - ods->fftformat = fftformat; - - ods->whiten = (odftype != ODS_ODF_MKL); // Deactivate whitening for MKL by default - ods->detected = false; - ods->med_odd = (medspan & 1) != 0; - - ods->medspan = medspan; - - ods->mingap = 0; - ods->gapleft = 0; - - ods->fftsize = fftsize; - ods->numbins = numbins; - - //printf("End of _init: normfactor is %g\n", ods->normfactor); - -} - -bool onsetsds_process(OnsetsDS* ods, float* fftbuf){ - onsetsds_loadframe(ods, fftbuf); - - onsetsds_whiten(ods); - onsetsds_odf(ods); - onsetsds_detect(ods); - - return ods->detected; -} - - -void onsetsds_setrelax(OnsetsDS* ods, float time, size_t hopsize){ - ods->relaxtime = time; - ods->relaxcoef = (time == 0.0f) ? 0.0f : exp((ods_log1 * hopsize)/(time * ods->srate)); -} - - - -void onsetsds_loadframe(OnsetsDS* ods, float* fftbuf){ - - float *pos, *pos2, imag, real; - int i; - - switch(ods->fftformat){ - case ODS_FFT_SC3_POLAR: - // The format is the same! dc, nyq, mag[1], phase[1], ... - memcpy(ods->curr, fftbuf, ods->fftsize * sizeof(float)); - break; - - case ODS_FFT_SC3_COMPLEX: - - ods->curr->dc = fftbuf[0]; - ods->curr->nyq = fftbuf[1]; - - // Then convert cartesian to polar: - pos = fftbuf + 2; - for(i=0; i< (ods->numbins << 1); i += 2){ - real = pos[i]; - imag = pos[i+1]; // Plus 1 rather than increment; seems to avoid LSU reject on my PPC - ods->curr->bin[i].mag = hypotf(imag, real); - ods->curr->bin[i].phase = atan2f(imag, real); - } - break; - - case ODS_FFT_FFTW3_HC: - - ods->curr->dc = fftbuf[0]; - ods->curr->nyq = fftbuf[ods->fftsize>>1]; - - // Then convert cartesian to polar: - // (Starting positions: real and imag for bin 1) - pos = fftbuf + 1; - pos2 = fftbuf + ods->fftsize - 1; - for(i=0; i<ods->numbins; i++){ - real = *(pos++); - imag = *(pos2--); - ods->curr->bin[i].mag = hypotf(imag, real); - ods->curr->bin[i].phase = atan2f(imag, real); - } - break; - - case ODS_FFT_FFTW3_R2C: - - ods->curr->dc = fftbuf[0]; - ods->curr->nyq = fftbuf[ods->fftsize]; - - // Then convert cartesian to polar: - pos = fftbuf + 2; - for(i=0; i<ods->numbins; i++){ - real = *(pos++); - imag = *(pos++); - ods->curr->bin[i].mag = hypotf(imag, real); - ods->curr->bin[i].phase = atan2f(imag, real); - } - break; - - } - - // Conversion to log-domain magnitudes, including re-scaling to aim back at the zero-to-one range. - // Not well tested yet. - if(ods->logmags){ - for(i=0; i<ods->numbins; i++){ - ods->curr->bin[i].mag = - (log(ods_max(ods->curr->bin[i].mag, ODS_LOG_LOWER_LIMIT)) - ODS_LOGOF_LOG_LOWER_LIMIT) * ODS_ABSINVOF_LOGOF_LOG_LOWER_LIMIT; - } - ods->curr->dc = - (log(ods_max(ods_abs(ods->curr->dc ), ODS_LOG_LOWER_LIMIT)) - ODS_LOGOF_LOG_LOWER_LIMIT) * ODS_ABSINVOF_LOGOF_LOG_LOWER_LIMIT; - ods->curr->nyq = - (log(ods_max(ods_abs(ods->curr->nyq), ODS_LOG_LOWER_LIMIT)) - ODS_LOGOF_LOG_LOWER_LIMIT) * ODS_ABSINVOF_LOGOF_LOG_LOWER_LIMIT; - } - -} - -void onsetsds_whiten(OnsetsDS* ods){ - - if(ods->whtype == ODS_WH_NONE){ - //printf("onsetsds_whiten(): ODS_WH_NONE, skipping\n"); - return; - } - - // NB: Apart from the above, ods->whtype is currently IGNORED and only one mode is used. - - - float val,oldval, relaxcoef, floor; - int numbins, i; - OdsPolarBuf *curr; - float *psp; - float *pspp1; // Offset by 1, avoids quite a lot of "+1"s in the following code - - relaxcoef = ods->relaxcoef; - numbins = ods->numbins; - curr = ods->curr; - psp = ods->psp; - pspp1 = psp + 1; - floor = ods->floor; - - //printf("onsetsds_whiten: relaxcoef=%g, relaxtime=%g, floor=%g\n", relaxcoef, ods->relaxtime, floor); - - ////////////////////// For each bin, update the record of the peak value ///////////////////// - - val = fabs(curr->dc); // Grab current magnitude - oldval = psp[0]; - // If it beats the amplitude stored then that's our new amplitude; - // otherwise our new amplitude is a decayed version of the old one - if(val < oldval) { - val = val + (oldval - val) * relaxcoef; - } - psp[0] = val; // Store the "amplitude trace" back - - val = fabs(curr->nyq); - oldval = pspp1[numbins]; - if(val < oldval) { - val = val + (oldval - val) * relaxcoef; - } - pspp1[numbins] = val; - - for(i=0; i<numbins; ++i){ - val = fabs(curr->bin[i].mag); - oldval = pspp1[i]; - if(val < oldval) { - val = val + (oldval - val) * relaxcoef; - } - pspp1[i] = val; - } - - //////////////////////////// Now for each bin, rescale the current magnitude //////////////////////////// - curr->dc /= ods_max(floor, psp[0]); - curr->nyq /= ods_max(floor, pspp1[numbins]); - for(i=0; i<numbins; ++i){ - curr->bin[i].mag /= ods_max(floor, pspp1[i]); - } -} - -void onsetsds_odf(OnsetsDS* ods){ - - int numbins = ods->numbins; - OdsPolarBuf *curr = ods->curr; - float* val = ods->odfvals; - int i, tbpointer; - float deviation, diff, curmag; - double totdev; - - bool rectify = true; - - // Here we shunt the "old" ODF values down one place - memcpy(val + 1, val, (ods->medspan - 1)*sizeof(float)); - - // Now calculate a new value and store in ods->odfvals[0] - switch(ods->odftype){ - case ODS_ODF_POWER: - - *val = (curr->nyq * curr->nyq) + (curr->dc * curr->dc); - for(i=0; i<numbins; i++){ - *val += curr->bin[i].mag * curr->bin[i].mag; - } - break; - - case ODS_ODF_MAGSUM: - - *val = ods_abs(curr->nyq) + ods_abs(curr->dc); - - for(i=0; i<numbins; i++){ - *val += ods_abs(curr->bin[i].mag); - } - break; - - case ODS_ODF_COMPLEX: - rectify = false; - // ...and then drop through to: - case ODS_ODF_RCOMPLEX: - - // Note: "other" buf is stored in this format: mag[0],phase[0],d_phase[0],mag[1],phase[1],d_phase[1], ... - - // Iterate through, calculating the deviation from expected value. - totdev = 0.0; - tbpointer = 0; - float predmag, predphase, yesterphase, yesterphasediff; - for (i=0; i<numbins; ++i) { - curmag = ods_abs(curr->bin[i].mag); - - // Predict mag as yestermag - predmag = ods->other[tbpointer++]; - yesterphase = ods->other[tbpointer++]; - yesterphasediff = ods->other[tbpointer++]; - - // Thresholding as Brossier did - discard (ignore) bin's deviation if bin's power is minimal - if(curmag > ods->odfparam) { - // If rectifying, ignore decreasing bins - if((!rectify) || !(curmag < predmag)){ - - // Predict phase as yesterval + yesterfirstdiff - predphase = yesterphase + yesterphasediff; - - // Here temporarily using the "deviation" var to store the phase difference - // so that the rewrap macro can use it more efficiently - deviation = predphase - curr->bin[i].phase; - - // Deviation is Euclidean distance between predicted and actual. - // In polar coords: sqrt(r1^2 + r2^2 - r1r2 cos (theta1 - theta2)) - deviation = sqrtf(predmag * predmag + curmag * curmag - - predmag * curmag * cosf(onsetsds_phase_rewrap(deviation)) - ); - - totdev += deviation; - } - } - } - - // totdev will be the output, but first we need to fill tempbuf with today's values, ready for tomorrow. - tbpointer = 0; - for (i=0; i<numbins; ++i) { - ods->other[tbpointer++] = ods_abs(curr->bin[i].mag); // Storing mag - diff = curr->bin[i].phase - ods->other[tbpointer]; // Retrieving yesterphase from buf - ods->other[tbpointer++] = curr->bin[i].phase; // Storing phase - // Wrap onto +-PI range - diff = onsetsds_phase_rewrap(diff); - - ods->other[tbpointer++] = diff; // Storing first diff to buf - - } - *val = (float)totdev; - - break; - - - case ODS_ODF_PHASE: - rectify = false; // So, actually, "rectify" means "useweighting" in this context - // ...and then drop through to: - case ODS_ODF_WPHASE: - - // Note: "other" buf is stored in this format: phase[0],d_phase[0],phase[1],d_phase[1], ... - - // Iterate through, calculating the deviation from expected value. - totdev = 0.0; - tbpointer = 0; - for (i=0; i<numbins; ++i) { - // Thresholding as Brossier did - discard (ignore) bin's phase deviation if bin's power is low - if(ods_abs(curr->bin[i].mag) > ods->odfparam) { - - // Deviation is the *second difference* of the phase, which is calc'ed as curval - yesterval - yesterfirstdiff - deviation = curr->bin[i].phase - ods->other[tbpointer++] - ods->other[tbpointer++]; - // Wrap onto +-PI range - deviation = onsetsds_phase_rewrap(deviation); - - if(rectify){ // "rectify" meaning "useweighting"... - totdev += fabs(deviation * ods_abs(curr->bin[i].mag)); - } else { - totdev += fabs(deviation); - } - } - } - - // totdev will be the output, but first we need to fill tempbuf with today's values, ready for tomorrow. - tbpointer = 0; - for (i=0; i<numbins; ++i) { - diff = curr->bin[i].phase - ods->other[tbpointer]; // Retrieving yesterphase from buf - ods->other[tbpointer++] = curr->bin[i].phase; // Storing phase - // Wrap onto +-PI range - diff = onsetsds_phase_rewrap(diff); - - ods->other[tbpointer++] = diff; // Storing first diff to buf - - } - *val = (float)totdev; - break; - - - case ODS_ODF_MKL: - - // Iterate through, calculating the Modified Kullback-Liebler distance - totdev = 0.0; - tbpointer = 0; - float yestermag; - for (i=0; i<numbins; ++i) { - curmag = ods_abs(curr->bin[i].mag); - yestermag = ods->other[tbpointer]; - - // Here's the main implementation of Brossier's MKL eq'n (eqn 2.9 from his thesis): - deviation = ods_abs(curmag) / (ods_abs(yestermag) + ods->odfparam); - totdev += log(1.f + deviation); - - // Store the mag as yestermag - ods->other[tbpointer++] = curmag; - } - *val = (float)totdev; - break; - - } - -#if ODS_DEBUG_POST_CSV - printf("%g,", *val); - printf("%g,", ods->odfvals[0] * ods->normfactor); -#endif - - ods->odfvals[0] *= ods->normfactor; -} -// End of ODF function - -void SelectionSort(float *array, int length); -void SelectionSort(float *array, int length) -{ - // Algo is simply based on http://en.wikibooks.org/wiki/Algorithm_implementation/Sorting/Selection_sort - int max, i; - float temp; - while(length > 0) - { - max = 0; - for(i = 1; i < length; i++) - if(array[i] > array[max]) - max = i; - temp = array[length-1]; - array[length-1] = array[max]; - array[max] = temp; - length--; - } -} - - -void onsetsds_detect(OnsetsDS* ods){ - - // Shift the yesterval to its rightful place - ods->odfvalpostprev = ods->odfvalpost; - - ///////// MEDIAN REMOVAL //////////// - - float* sortbuf = ods->sortbuf; - int medspan = ods->medspan; - - // Copy odfvals to sortbuf - memcpy(sortbuf, ods->odfvals, medspan * sizeof(float)); - - // Sort sortbuf - SelectionSort(sortbuf, medspan); - - // Subtract the middlest value === the median - if(ods->med_odd){ - ods->odfvalpost = ods->odfvals[0] - - sortbuf[(medspan - 1) >> 1]; - }else{ - ods->odfvalpost = ods->odfvals[0] - - ((sortbuf[medspan >> 1] - + sortbuf[(medspan >> 1) - 1]) * 0.5f); - - } - - // Detection not allowed if we're too close to a previous detection. - if(ods->gapleft != 0) { - ods->gapleft--; - ods->detected = false; - } else { - // Now do the detection. - ods->detected = (ods->odfvalpost > ods->thresh) && (ods->odfvalpostprev <= ods->thresh); - if(ods->detected){ - ods->gapleft = ods->mingap; - } - } -#if ODS_DEBUG_POST_CSV - printf("%g\n", ods->odfvalpost); -#endif -} - -
--- a/onsetsds/onsetsds.h Wed Jul 09 12:56:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,275 +0,0 @@ -/* - OnsetsDS - real time musical onset detection library. - Copyright (c) 2007 Dan Stowell. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** \file */ - -#ifndef _OnsetsDS_ -#define _OnsetsDS_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdio.h> -#include <string.h> -#include <stdbool.h> -#include <math.h> - - -//////////////////////////////////////////////////////////////////////////////// -// Macros and consts - -//log(0.1) -#define ods_log1 -2.30258509 - -#define PI 3.1415926535898f -#define MINUSPI -3.1415926535898f -#define TWOPI 6.28318530717952646f -#define INV_TWOPI 0.1591549430919f - -#define ods_abs(a) ((a)<0? -(a) : (a)) -#define ods_max(a,b) (((a) > (b)) ? (a) : (b)) -#define ods_min(a,b) (((a) < (b)) ? (a) : (b)) - -#define ODS_LOG_LOWER_LIMIT 2e-42 -#define ODS_LOGOF_LOG_LOWER_LIMIT -96.0154267 -#define ODS_ABSINVOF_LOGOF_LOG_LOWER_LIMIT 0.010414993 - -//////////////////////////////////////////////////////////////////////////////// -// Constants - -/** -* Types of incoming FFT data format. OnsetsDS needs to know where the FFT -* data comes from in order to interpret it correctly. -*/ -enum onsetsds_fft_types { - ODS_FFT_SC3_COMPLEX, ///< SuperCollider, cartesian co-ords ("SCComplexBuf") - NB it's more efficient to provide polar data from SC - ODS_FFT_SC3_POLAR, ///< SuperCollider, polar co-ords ("SCPolarBuf") - ODS_FFT_FFTW3_HC, ///< FFTW <a href="http://www.fftw.org/fftw3_doc/The-Halfcomplex_002dformat-DFT.html">"halfcomplex"</a> format - ODS_FFT_FFTW3_R2C ///< FFTW regular format, typically produced using <a href="http://www.fftw.org/fftw3_doc/One_002dDimensional-DFTs-of-Real-Data.html#One_002dDimensional-DFTs-of-Real-Data">real-to-complex</a> transform -}; - -/** -* Types of onset detection function -*/ -enum onsetsds_odf_types { - ODS_ODF_POWER, ///< Power - ODS_ODF_MAGSUM, ///< Sum of magnitudes - ODS_ODF_COMPLEX, ///< Complex-domain deviation - ODS_ODF_RCOMPLEX, ///< Complex-domain deviation, rectified (only increases counted) - ODS_ODF_PHASE, ///< Phase deviation - ODS_ODF_WPHASE, ///< Weighted phase deviation - ODS_ODF_MKL ///< Modified Kullback-Liebler deviation -}; - -/** -* Types of whitening - may not all be implemented yet. -*/ -enum onsetsds_wh_types { - ODS_WH_NONE, ///< No whitening - onsetsds_whiten() becomes a no-op - ODS_WH_ADAPT_MAX1, ///< Adaptive whitening - tracks recent-peak-magnitude in each bin, normalises that to 1 - ODS_WH_NORMMAX, ///< Simple normalisation - each frame is normalised (independent of others) so largest magnitude becomes 1. Not implemented. - ODS_WH_NORMMEAN ///< Simple normalisation - each frame is normalised (independent of others) so mean magnitude becomes 1. Not implemented. -}; - -//////////////////////////////////////////////////////////////////////////////// -// Structs - -typedef struct OdsPolarBin { float mag, phase; } OdsPolarBin; - -typedef struct OdsPolarBuf { - float dc, nyq; - OdsPolarBin bin[1]; -} OdsPolarBuf; - -/// The main data structure for the onset detection routine -typedef struct OnsetsDS { - /// "data" is a pointer to the memory that must be EXTERNALLY allocated. - /// Other pointers will point to locations within this memory. - float *data, - *psp, ///< Peak Spectral Profile - size is numbins+2, data is stored in order dc through to nyquist - *odfvals, // odfvals[0] will be the current val, odfvals[1] prev, etc - *sortbuf, // Used to calculate the median - *other; // Typically stores data about the previous frame - OdsPolarBuf* curr; // Current FFT frame, as polar - - float - srate, ///< The sampling rate of the input audio. Set by onsetsds_init() - // Adaptive whitening params - relaxtime, ///< Do NOT set this directly. Use onsetsds_setrelax() which will also update relaxcoef. - relaxcoef, ///< Relaxation coefficient (memory coefficient). See also onsetsds_setrelax() - floor, ///< floor - the lowest value that a PSP magnitude can take. - /// A parameter for the ODF. For most this is a magnitude threshold for a single bin to be considered; - /// but for #ODS_ODF_MKL it is the "epsilon" parameter. - odfparam, - /// Value used internally to scale ODF value according to the FFT frame size. Automatically set by onsetsds_init() - normfactor, - // ODF val after median processing - odfvalpost, - // Previous val is needed for threshold-crossing detection - odfvalpostprev, - /// Threshold (of ODF value, after median processing) for detection. - /// Values between 0 and 1 are expected, but outside this range may - /// sometimes be appropriate too. - thresh; - - int odftype, ///< Choose from #onsetsds_odf_types - whtype, ///< Choose from #onsetsds_wh_types - fftformat; ///< Choose from #onsetsds_fft_types - bool whiten, ///< Whether to apply whitening - onsetsds_init() decides this on your behalf - detected,///< Output val - true if onset detected in curr frame - /** - NOT YET USED: Whether to convert magnitudes to log domain before processing. This is done as follows: - Magnitudes below a log-lower-limit threshold (ODS_LOG_LOWER_LIMIT) are pushed up to that threshold (to avoid log(0) infinity problems), - then the log is taken. The values are re-scaled to a similar range as the linear-domain values (assumed to lie - between zero and approximately one) by subtracting log(ODS_LOG_LOWER_LIMIT) and then dividing by abs(log(ODS_LOG_LOWER_LIMIT)). - */ - logmags, - med_odd; ///< Whether median span is odd or not (used internally) - - unsigned int - /// Number of frames used in median calculation - medspan, - /// Size of enforced gap between detections, measured in FFT frames. - mingap, gapleft; - size_t fftsize, numbins; // numbins is the count not including DC/nyq -} OnsetsDS; - - -//////////////////////////////////////////////////////////////////////////////// -// Function prototypes - - -/** - * \defgroup MainUserFuncs Main user functions - */ - //@{ - -/** -* Determine how many bytes of memory must be allocated (e.g. using malloc) to -* accompany the OnsetsDS struct, operating using the specified settings (used to -* store part-processed FFT data etc). The user must -* call this, and then allocate the memory, BEFORE calling onsetsds_init(). -* @param odftype Which onset detection function (ODF) you'll be using, chosen from #onsetsds_odf_types -* @param fftsize Size of FFT: 512 is recommended. -* @param medspan The number of past frames that will be used for median calculation during triggering -*/ -size_t onsetsds_memneeded (int odftype, size_t fftsize, unsigned int medspan); - -/** -* Initialise the OnsetsDS struct and its associated memory, ready to detect -* onsets using the specified settings. Must be called before any call to -* onsetsds_process(). -* -* Note: you can change the onset detection function type in mid-operation -* by calling onsetsds_init() again, but because memory will be reset this -* will behave as if starting from scratch (rather than being aware of the past -* few frames of sound). Do not attempt to change the -* onset detection function in a more hacky way (e.g. fiddling with the struct) -* because memory is set up differently for each of the different ODFs. -* @param ods An instance of the OnsetsDS struct -* @param odsdata A pointer to the memory allocated, size given by onsetsds_memneeded(). -* @param fftformat Which format of FFT data is to be expected, chosen from #onsetsds_fft_types -* @param odftype Which onset detection function (ODF) you'll be using, chosen from #onsetsds_odf_types -* @param fftsize Size of FFT: 512 or 1024 is recommended. -* @param medspan The number of past frames that will be used for median calculation during triggering -* @param srate The sampling rate of the input audio -*/ -void onsetsds_init(OnsetsDS* ods, float* odsdata, int fftformat, - int odftype, size_t fftsize, unsigned int medspan, float srate); - -/** -* Process a single FFT data frame in the audio signal. Note that processing -* assumes that each call to onsetsds_process() is on a subsequent frame in -* the same audio stream - to handle multiple streams you must use separate -* OnsetsDS structs and memory! -* -* This function's main purpose is to call some of the library's other functions, -* in the expected sequence. -*/ -bool onsetsds_process(OnsetsDS* ods, float* fftbuf); - -//@} - - -//////////////////////////////////////////////////////////////////////////////// -// Function prototypes less commonly called by users - -/** - * \defgroup LessCommonFuncs Other useful functions - */ - //@{ -/** -* Set the "memory coefficient" indirectly via the time for the -* memory to decay by 60 dB. -* @param ods The OnsetsDS -* @param time The time in seconds -* @param hopsize The FFT frame hopsize (typically this will be half the FFT frame size) -*/ -void onsetsds_setrelax(OnsetsDS* ods, float time, size_t hopsize); - -//@} - -//////////////////////////////////////////////////////////////////////////////// -// Function prototypes not typically called by users - -/** - * \defgroup OtherFuncs Other functions, not typically called by users - */ - //@{ -/** -* Load the current frame of FFT data into the OnsetsDS struct. -* -* Not typically called directly by users since onsetsds_process() calls this. -*/ -void onsetsds_loadframe(OnsetsDS* ods, float* fftbuf); - -/** -* Apply adaptive whitening to the FFT data in the OnsetsDS struct. -* -* Not typically called directly by users since onsetsds_process() calls this. -*/ -void onsetsds_whiten(OnsetsDS* ods); - -/** -* Calculate the Onset Detection Function (includes scaling ODF outputs to -* similar range) -* -* Not typically called directly by users since onsetsds_process() calls this. -*/ -void onsetsds_odf(OnsetsDS* ods); - -/** -* Detects salient peaks in Onset Detection Function by removing the median, -* then thresholding. Afterwards, the member ods.detected will indicate whether -* or not an onset was detected. -* -* Not typically called directly by users since onsetsds_process() calls this. -*/ -void onsetsds_detect(OnsetsDS* ods); - -//@} - -//////////////////////////////////////////////////////////////////////////////// - -#ifdef __cplusplus -} -#endif - -#endif
--- a/onsetsds/onsetsdshelpers.c Wed Jul 09 12:56:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - OnsetsDS - real time musical onset detection library. - Copyright (c) 2007 Dan Stowell. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "onsetsdshelpers.h" - -#include <stdlib.h> -#include <sndfile.h> -#include <fftw3.h> - -void onsetsds_init_audiodata(OnsetsDSAudioBuf *odsbuf, OnsetsDS *ods, /* size_t framesize, */ size_t hopsize){ - - odsbuf->ods = ods; - odsbuf->buflen = ods->fftsize; - odsbuf->hopsize = hopsize; - - size_t framesizebytes = ods->fftsize * sizeof(float); - - // malloc odsbuf.data, odsbuf.window, odsbuf.windoweddata - odsbuf->data = (float*) malloc(framesizebytes); - odsbuf->window = (float*) malloc(framesizebytes); - odsbuf->windoweddata = (float*) fftwf_malloc(framesizebytes); - odsbuf->fftbuf = (float*) fftwf_malloc(framesizebytes); - - // Create the FFTW plan - odsbuf->fftplan = fftwf_plan_r2r_1d(ods->fftsize, odsbuf->windoweddata, odsbuf->fftbuf, FFTW_R2HC, FFTW_ESTIMATE); - - // zero odsbuf.data - memset(odsbuf->data, 0, framesizebytes); - - // Create the FFT window - double pi = acos(-1.); - double winc = pi / ods->fftsize; - int i; - for (i=0; i<ods->fftsize; ++i) { - double w = i * winc; - odsbuf->window[i] = sin(w); - } - - odsbuf->sampsElapsed = 0L; - odsbuf->writepos = 0; -} -void onsetsds_destroy_audiodata(OnsetsDSAudioBuf *odsbuf){ - // take down the FFTW stuff - fftwf_destroy_plan(odsbuf->fftplan); - // free mem - free(odsbuf->data); - free(odsbuf->window); - fftwf_free(odsbuf->windoweddata); - fftwf_free(odsbuf->fftbuf); -} - -void onsetsds_process_audiodata(OnsetsDSAudioBuf* odsbuf, float* data, size_t datalen, - ODSDataCallback callback){ - - if(datalen==0){ - printf("onsetsds_process_audiodata GRRRRRR: no audio data sent (datalen==0)\n"); - return; - }else{ - } - - size_t datareadpos = 0; - size_t dataleft = datalen; - size_t numtocopy; - int i; - while(dataleft > 0){ - // Read the smaller of how-much-available and how-much-to-fill-the-buffer - numtocopy = ods_min(dataleft, odsbuf->buflen - odsbuf->writepos); -// printf("onsetsds_process_audiodata: datalen = %i, dataleft = %i, buflen = %i, about to copy %i values to position %i\n", -// datalen, dataleft, odsbuf->buflen, numtocopy, odsbuf->writepos); - memcpy(&odsbuf->data[odsbuf->writepos], &data[datareadpos], numtocopy * sizeof(float)); - - odsbuf->writepos += numtocopy; - - // If the buffer is full, do all the FFT and stuff - if(odsbuf->writepos >= odsbuf->buflen){ - - // Copy the data into the buffer where windowing and FFT takes place - memcpy(odsbuf->windoweddata, odsbuf->data, odsbuf->buflen * sizeof(float)); - - // Shunt the audio data (and the writepos) down to make room for the next lot - memcpy(odsbuf->data, &odsbuf->data[odsbuf->hopsize], (odsbuf->buflen - odsbuf->hopsize) * sizeof(float)); - //printf("onsetsds_process_audiodata: moving writepos from %i to %i(==hopsize)\n", odsbuf->writepos, odsbuf->hopsize); - odsbuf->writepos = odsbuf->hopsize; - - // Windowing - for(i=0; i<odsbuf->buflen; i++){ - odsbuf->windoweddata[i] *= odsbuf->window[i]; - } - - // FFT - fftwf_execute(odsbuf->fftplan); - - // Onset detection - if(onsetsds_process(odsbuf->ods, odsbuf->fftbuf)){ - // Call the callback! - callback(odsbuf, datareadpos); - } - - } // End buffer-is-filled - - datareadpos += numtocopy; - dataleft -= numtocopy; - } // End of still-some-data-to-push - -} - - -void onsetsds_process_audiofile_CALLBACK(OnsetsDSAudioBuf* odsbuf, size_t onsetsamplepos); -void onsetsds_process_audiofile_CALLBACK(OnsetsDSAudioBuf* odsbuf, size_t onsetsamplepos){ - // Convert the sample pos into a seconds position through the whole file - double secs = (odsbuf->sampsElapsed + onsetsamplepos) / odsbuf->samplerate; - - // Now call the file-level callback - (odsbuf->filecallback)(odsbuf->ods, secs); -} - -int onsetsds_process_audiofile(OnsetsDSAudioBuf* odsbuf, const char *infilename, - ODSFileCallback callback){ - - SNDFILE *insndfile ; - SF_INFO sfinfo ; - memset (&sfinfo, 0, sizeof (sfinfo)); - - // Attempt to get the input file - if ((insndfile = sf_open (infilename, SFM_READ, &sfinfo)) == NULL){ - printf ("onsetsds_process_audiofile ERROR: Not able to open input file %s.\n", infilename) ; - fflush (stdout) ; - return 100; - } - if(sfinfo.channels != 1){ - printf("onsetsds_process_audiofile ERROR: Only mono audio files can be processed. Num channels = %i. Exiting.\n", sfinfo.channels); - sf_close(insndfile); - return 200; - }else{ - printf("onsetsds_process_audiofile: mono audio file, sample rate %i Hz.\n", sfinfo.samplerate); - } - - odsbuf->sampsElapsed = 0L; - odsbuf->samplerate = (double) sfinfo.samplerate; - odsbuf->filecallback = callback; - - // Create a buffer for reading the raw data into - float* data = malloc(odsbuf->buflen * sizeof(float)); - - sf_count_t numread; - //printf("onsetsds_process_audiofile: Processing audio data\n", numread); - while((numread = sf_read_float(insndfile, data, odsbuf->buflen)) > 0){ - //printf("Read %i audio frames (requested %i)\n", numread, odsbuf->buflen); - - //printf("Calling onsetsds_process_audiodata\n"); - onsetsds_process_audiodata(odsbuf, data, numread, onsetsds_process_audiofile_CALLBACK); - //printf("Called onsetsds_process_audiodata\n"); - odsbuf->sampsElapsed += numread; - } - - sf_close(insndfile); - free(data); - - // Indicate success - return 0; -}
--- a/onsetsds/onsetsdshelpers.h Wed Jul 09 12:56:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,171 +0,0 @@ -/* - OnsetsDS - real time musical onset detection library. - Copyright (c) 2007 Dan Stowell. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/** \file */ - -/** - * \defgroup HelperFuncs Convenience functions to apply OnsetsDS to a chunk of audio data, or to an audio file. - * - * These functions are NOT required in order to use the core OnsetsDS functionality, but provide wrappers to - * make it easy to apply OnsetsDS to time-domain data (audio chunks, or audio files) without having to write the - * FFT processing yourself. - */ - //@{ - -#ifndef _OnsetsDSHelpers_ -#define _OnsetsDSHelpers_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <fftw3.h> -#include "../onsetsds.h" - -//////////////////////////////////////////////////////////////////////////////// - -/** -When using onsetsds_process_audiofile(), this specifies that your callback function should -take an #OnsetsDS and a double as arguments, and return void. The double will be a time -offset, from the beginning of the recording, at which the detected onset occurred. -*/ -typedef void (*ODSFileCallback)(OnsetsDS*, double); - -/** -Holds all the state data required by onsetsds_process_audiodata(), including a pointer to an #OnsetsDS -as well as the time-domain/freq-domain buffers. -Also remembers the FFT frame size, hop size. -*/ -typedef struct OnsetsDSAudioBuf{ - OnsetsDS* ods; - - size_t buflen; - size_t hopsize; - size_t writepos; - float *data; // size will be buflen - float *window; // size will be buflen - float *windoweddata; // size will be buflen - float *fftbuf; // size will be buflen - fftwf_plan fftplan; - - // Whole-file-only things (i.e. unused when you're pushing audio blocks yourself): - long sampsElapsed; - double samplerate; - ODSFileCallback filecallback; -} OnsetsDSAudioBuf; - -/** -When using onsetsds_process_audiodata(), this specifies that your callback function should -take an #OnsetsDSAudioBuf and a size_t as arguments, and return void. The size_t will be a sample -offset at which the detected onset occurred, within the audio frame that was just passed in. (More than -one onset per audio frame is possible, depending on how much data you're passing in at a time.) -*/ -typedef void (*ODSDataCallback)(OnsetsDSAudioBuf*, size_t); - -/** -This data structure stores statistics derived from using onsetsds_evaluate_audiofile(), describing how well -the onset detector matched the "ground truth" annotations. -*/ -typedef struct OnsetsDSEvalData{ - long numGT; ///< How many ground truth annotations were provided - long numAnnot; ///< How many onsets it found - long numTP; ///< How many correct detections occurred - long numFP; ///< How many false positives occurred - long numFN; ///< How many false negatives occurred - - float precision; ///< 0 to 1: a measure of resistance against false positives - float recall; ///< 0 to 1: a measure of resistance against false negatives - float f; ///< 0 to 1: the "F-measure", a combination of the precision and recall statistics - - float devimean; ///< Mean of each onset's deviation from the annotated onset, a rough indicator of reacting "too quickly"/"too slowly" - float deviabsmean; ///< Absolute mean of each onset's deviation from the annotated onset, a rough indicator of temporal accuracy - float devisd; ///< Standard deviation re devimean, useful when combining stats - float deviabssd; ///< Standard deviation re deviabsmean, useful when combining stats -} OnsetsDSEvalData; - -//////////////////////////////////////////////////////////////////////////////// - -/** -Set up the data structures for use by onsetsds_process_audiodata(). - -@param odsbuf Will be set up nicely by this function. -@param ods Must have been initialised properly before calling this function. -@param hopsize Hop size in samples (256 is recommended) -*/ -void onsetsds_init_audiodata(OnsetsDSAudioBuf* odsbuf, OnsetsDS* ods, size_t hopsize); -/** -Correctly deallocate and destroy the #OnsetsDSAudioBuf. Use this after onsetsds_process_audiofile(), or after you've finished -running a series of onsetsds_process_audiodata() calls. - -@param odsbuf -*/ -void onsetsds_destroy_audiodata(OnsetsDSAudioBuf* odsbuf); - -/** -Process a new chunk of audio data. - -@param odsbuf Must have been initialised properly before calling this function, using onsetsds_init_audiodata() -@param data The *new* chunk of mono, time-domain audio data. Internal buffers will handle frame overlap etc. The size - of the input data does *not* need to have a relation to the frame size or hop size. -@param datalen Size of the data buffer. -@param callback Name of your callback function, which will be called whenever an onset is detected. - It will be passed the #OnsetsDSAudioBuf object and (more importantly) the sample offset at which the onset was detected - (i.e. a value between 0 and datalen). -*/ -void onsetsds_process_audiodata(OnsetsDSAudioBuf* odsbuf, float* data, size_t datalen, - ODSDataCallback callback); - -//////////////////////////////////////////////////////////////////////////////// - -/** -Process an entire file of audio data. Returns 0 if successful (may fail if it can't find/open the audio file, for example). - -@param odsbuf Must have been initialised properly before calling this function, using onsetsds_init_audiodata() -@param infilename The file to be loaded. -@param callback Name of your callback function, which will be called whenever an onset is detected. - It will be passed the #OnsetsDS object and (more importantly) the time offset in seconds at which the onset was detected - (a double-precision-floating-point value between 0 and the duration of the audio file). -*/ -int onsetsds_process_audiofile(OnsetsDSAudioBuf* odsbuf, const char *infilename, - ODSFileCallback callback); - -/** -Process an entire file of audio data and compare the onset detector's output against a single "ground truth" annotation of where the -onsets really are. - -@param odsbuf Must have been initialised properly before calling this function, using onsetsds_init_audiodata() -@param infilename The file to be loaded. -@param gtfilename The file containing a text list of ground-truth annotations, one number per line, each being an onset's - position in seconds from the beginning of the file. The numbers must be in ascending order. - This format can be easily exported from programs - such as <a href="http://www.sonicvisualiser.org/">Sonic Visualiser</a>. -@param results Pointer to the #OnsetsDSEvalData where the results should be written. - -*/ -int onsetsds_evaluate_audiofile(OnsetsDSAudioBuf* odsbuf, const char *infilename, const char *gtfilename, OnsetsDSEvalData* results); - -//////////////////////////////////////////////////////////////////////////////// - -#ifdef __cplusplus -} -#endif - -#endif - -//@}