changeset 0:635e8745ccc9

* First commit of plugin using Dan Stowell's OnsetsDS library code
author cannam
date Thu, 19 Jun 2008 12:30:15 +0000
parents
children 3d1928670329
files AUTHORS COPYING Makefile 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 onsetsdsplugin.cpp onsetsdsplugin.h vamp-onsetsds.cat
diffstat 17 files changed, 2623 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AUTHORS	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,5 @@
+
+Dan Stowell, dan.stowell@elec.qmul.ac.uk
+
+Vamp-plugin-ified by Chris Cannam, cannam@all-day-breakfast.com
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/COPYING	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,13 @@
+
+CXXFLAGS	:= -I../vamp-plugin-sdk -O3 -Wall
+#CXXFLAGS	:= -I../vamp-plugin-sdk -g -Wall -march=pentium4 -msse -msse2 -ffast-math
+#CXXFLAGS	:= -I../vamp-plugin-sdk -O3 -Wall -march=pentium4 -msse -msse2 -fomit-frame-pointer -ffast-math
+
+vamp-onsetsds.so:	onsetsdsplugin.o onsetsds/onsetsds.o
+	g++ -shared $^ -o $@ -L../vamp-plugin-sdk/vamp-sdk -Wl,-Bstatic -lvamp-sdk -Wl,-Bdynamic -lpthread
+
+clean:	
+	rm -f *.o */*.o
+
+onsetsdsplugin.o: onsetsdsplugin.h onsetsds/onsetsds.h 
+onsetsds/onsetsds.o: onsetsds/onsetsds.h 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsds/AUTHORS	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,2 @@
+
+Dan Stowell, dan.stowell@elec.qmul.ac.uk
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsds/COPYING	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsds/ChangeLog	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,3 @@
+2007-11  Dan Stowell
+    * Significant refactoring from v0.1, which was a set of SuperCollider UGens.
+    * VERSION: 0.2.0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsds/README	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,29 @@
+
+ ----------------------------------------------------------
+ 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.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsds/doc/Doxyfile	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,267 @@
+# 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsds/doc/footer.html	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,1 @@
+</body></html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsds/doc/mainpage.dox	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,93 @@
+/** \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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsds/onsetsds.c	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,547 @@
+/*
+	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
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsds/onsetsds.h	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,275 @@
+/*
+    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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsds/onsetsdshelpers.c	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,177 @@
+/*
+	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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsds/onsetsdshelpers.h	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,171 @@
+/*
+	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
+
+//@}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsdsplugin.cpp	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,286 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+/*
+    Vamp feature extraction plugin using the OnsetsDS onset detector.
+    This file copyright (c) 2008 Chris Cannam.
+
+    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 "onsetsdsplugin.h"
+#include <vamp-sdk/PluginAdapter.h>
+
+using std::string;
+using std::vector;
+using std::cerr;
+using std::endl;
+
+
+OnsetsDSPlugin::OnsetsDSPlugin(float inputSampleRate) :
+    Vamp::Plugin(inputSampleRate),
+    m_ods(0),
+    m_odsdata(0),
+    m_dfType(ODS_ODF_RCOMPLEX),
+    m_medspan(11),
+    m_stepSize(512),
+    m_fftSize(1024)
+{
+}
+
+OnsetsDSPlugin::~OnsetsDSPlugin()
+{
+    delete[] m_odsdata;
+    delete m_ods;
+}
+
+string
+OnsetsDSPlugin::getIdentifier() const
+{
+    return "onsetsds";
+}
+
+string
+OnsetsDSPlugin::getName() const
+{
+    return "OnsetsDS Onset Detector";
+}
+
+string
+OnsetsDSPlugin::getDescription() const
+{
+    return "Detect note onsets";
+}
+
+string
+OnsetsDSPlugin::getMaker() const
+{
+    return "Dan Stowell";
+}
+
+int
+OnsetsDSPlugin::getPluginVersion() const
+{
+    return 1;
+}
+
+string
+OnsetsDSPlugin::getCopyright() const
+{
+    return "Copyright (c) 2007-2008 Dan Stowell";
+}
+
+OnsetsDSPlugin::ParameterList
+OnsetsDSPlugin::getParameterDescriptors() const
+{
+    ParameterList list;
+
+    ParameterDescriptor desc;
+    desc.identifier = "dftype";
+    desc.name = "Onset detection function";
+    desc.description = "Method used to calculate the onset detection function";
+    desc.minValue = 0;
+    desc.maxValue = 6;
+    desc.defaultValue = 3;
+    desc.isQuantized = true;
+    desc.quantizeStep = 1;
+    desc.valueNames.push_back("Power");
+    desc.valueNames.push_back("Sum of magnitudes");
+    desc.valueNames.push_back("Complex-domain deviation");
+    desc.valueNames.push_back("Rectified complex-domain deviation");
+    desc.valueNames.push_back("Phase deviation");
+    desc.valueNames.push_back("Weighted phase deviation");
+    desc.valueNames.push_back("Modified Kullback-Liebler deviation");
+    list.push_back(desc);
+
+    desc.identifier = "medspan";
+    desc.name = "Median frame span";
+    desc.description = "Number of past frames used in median calculation";
+    desc.minValue = 5;
+    desc.maxValue = 21;
+    desc.defaultValue = 11;
+    desc.isQuantized = true;
+    desc.quantizeStep = 2;
+    desc.valueNames.clear();
+    list.push_back(desc);
+
+    return list;
+}
+
+float
+OnsetsDSPlugin::getParameter(std::string name) const
+{
+    if (name == "dftype") {
+        switch (m_dfType) {
+        case ODS_ODF_POWER:    return 0;
+        case ODS_ODF_MAGSUM:   return 1;
+        case ODS_ODF_COMPLEX:  return 2;
+        case ODS_ODF_RCOMPLEX: return 3;
+        case ODS_ODF_PHASE:    return 4;
+        case ODS_ODF_WPHASE:   return 5;
+        case ODS_ODF_MKL:      return 6;
+        }
+    } else if (name == "medspan") {
+        return m_medspan;
+    }
+    return 0.0;
+}
+
+void
+OnsetsDSPlugin::setParameter(std::string name, float value)
+{
+    if (name == "dftype") {
+        onsetsds_odf_types dfType = m_dfType;
+        switch (lrintf(value)) {
+        case 0: dfType = ODS_ODF_POWER; break;
+        case 1: dfType = ODS_ODF_MAGSUM; break;
+        case 2: dfType = ODS_ODF_COMPLEX; break;
+        case 3: dfType = ODS_ODF_RCOMPLEX; break;
+        case 4: dfType = ODS_ODF_PHASE; break;
+        case 5: dfType = ODS_ODF_WPHASE; break;
+        case 6: dfType = ODS_ODF_MKL; break;
+        }
+        if (dfType == m_dfType) return;
+        m_dfType = dfType;
+    } else if (name == "medspan") {
+        m_medspan = lrintf(value);
+    }
+}
+
+bool
+OnsetsDSPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    if (channels < getMinChannelCount() ||
+	channels > getMaxChannelCount()) {
+        std::cerr << "OnsetsDSPlugin::initialise: Unsupported channel count: "
+                  << channels << std::endl;
+        return false;
+    }
+
+    if (stepSize != getPreferredStepSize()) {
+        std::cerr << "WARNING: OnsetsDSPlugin::initialise: Using unusual step size: "
+                  << stepSize << " (wanted " << (getPreferredStepSize()) << ")" << std::endl;
+    }
+
+    if (blockSize != getPreferredBlockSize()) {
+        std::cerr << "WARNING: OnsetsDSPlugin::initialise: Using unusual block size: "
+                  << blockSize << " (wanted " << (getPreferredBlockSize()) << ")" << std::endl;
+    }
+
+    m_stepSize = stepSize;
+    m_fftSize = blockSize;
+
+    delete[] m_odsdata;
+    delete m_ods;
+
+    m_odsdata = new float[onsetsds_memneeded(m_dfType, m_fftSize, m_medspan)];
+    m_ods = new OnsetsDS;
+    memset(m_ods, 0, sizeof(OnsetsDS));
+    onsetsds_init(m_ods, m_odsdata, ODS_FFT_FFTW3_R2C, m_dfType, m_fftSize,
+                  m_medspan, m_inputSampleRate);
+
+    return true;
+}
+
+void
+OnsetsDSPlugin::reset()
+{
+    if (!m_ods) {
+        std::cerr << "ERROR: OnsetsDSPlugin::reset: Plugin has not been initialised" << std::endl;
+        return;
+    }
+    onsetsds_init(m_ods, m_odsdata, ODS_FFT_FFTW3_R2C, m_dfType, m_fftSize,
+                  m_medspan, m_inputSampleRate);
+}
+
+size_t
+OnsetsDSPlugin::getPreferredStepSize() const
+{
+    return 512;
+}
+
+size_t
+OnsetsDSPlugin::getPreferredBlockSize() const
+{
+    return 1024;
+}
+
+OnsetsDSPlugin::OutputList
+OnsetsDSPlugin::getOutputDescriptors() const
+{
+    OutputList list;
+
+    OutputDescriptor onsets;
+    onsets.identifier = "onsets";
+    onsets.name = "Note Onsets";
+    onsets.description = "Note onset positions";
+    onsets.unit = "";
+    onsets.hasFixedBinCount = true;
+    onsets.binCount = 0;
+    onsets.sampleType = OutputDescriptor::VariableSampleRate;
+    onsets.sampleRate = (m_inputSampleRate / m_stepSize);
+
+    list.push_back(onsets);
+
+    return list;
+}
+
+OnsetsDSPlugin::FeatureSet
+OnsetsDSPlugin::process(const float *const *inputBuffers,
+                       Vamp::RealTime timestamp)
+{
+    if (!m_ods) {
+	cerr << "ERROR: OnsetsDSPlugin::process: Plugin has not been initialised"
+	     << endl;
+	return FeatureSet();
+    }
+
+    // We can const_cast because we happen to know onsetsds_process
+    // does not modify this buffer
+    bool result = onsetsds_process(m_ods, const_cast<float *>(inputBuffers[0]));
+
+    FeatureSet returnFeatures;
+
+    if (result) {
+        Feature feature;
+        feature.hasTimestamp = true;
+        feature.timestamp = timestamp;
+        returnFeatures[0].push_back(feature); // onsets are output 0
+    }
+
+    return returnFeatures;
+}
+
+OnsetsDSPlugin::FeatureSet
+OnsetsDSPlugin::getRemainingFeatures()
+{
+    return FeatureSet();
+}
+
+
+static Vamp::PluginAdapter<OnsetsDSPlugin> adapter;
+
+const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
+                                                    unsigned int index)
+{
+    if (version < 1) return 0;
+
+    switch (index) {
+    case  0: return adapter.getDescriptor();
+    default: return 0;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/onsetsdsplugin.h	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,73 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+/*
+    Vamp feature extraction plugin using the OnsetsDS onset detector.
+    This file copyright (c) 2008 Chris Cannam.
+
+    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
+*/
+
+#ifndef _ONSETSDS_PLUGIN_H_
+#define _ONSETSDS_PLUGIN_H_
+
+#include <vamp-sdk/Plugin.h>
+
+#include "onsetsds/onsetsds.h"
+
+class OnsetsDSPlugin : public Vamp::Plugin
+{
+public:
+    OnsetsDSPlugin(float inputSampleRate);
+    virtual ~OnsetsDSPlugin();
+
+    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;
+
+    ParameterList getParameterDescriptors() const;
+    float getParameter(std::string) const;
+    void setParameter(std::string, float);
+
+    size_t getPreferredStepSize() const;
+    size_t getPreferredBlockSize() const;
+
+    OutputList getOutputDescriptors() const;
+
+    FeatureSet process(const float *const *inputBuffers,
+                       Vamp::RealTime timestamp);
+
+    FeatureSet getRemainingFeatures();
+
+protected:
+    OnsetsDS *m_ods;
+    float *m_odsdata;
+    onsetsds_odf_types m_dfType;
+    size_t m_medspan;
+    size_t m_stepSize;
+    size_t m_fftSize;
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-onsetsds.cat	Thu Jun 19 12:30:15 2008 +0000
@@ -0,0 +1,1 @@
+vamp:vamp-onsetsds:onsetsds::Time > Onsets