changeset 21:d660db57e902

Rearrange code, include subrepo etc
author Chris Cannam
date Thu, 05 Feb 2015 10:13:31 +0000
parents 331a520cdadb
children de942cbe5b27
files .hgsub .hgsubstate COPYING Makefile.inc Makefile.linux Makefile.mingw32 Makefile.osx README chroma-compare-plugin/Makefile.inc chroma-compare-plugin/Makefile.linux chroma-compare-plugin/Makefile.mingw32 chroma-compare-plugin/Makefile.osx chroma-compare-plugin/TuningDifference.cpp chroma-compare-plugin/TuningDifference.h chroma-compare-plugin/plugins.cpp chroma-compare-plugin/vamp-plugin.list chroma-compare-plugin/vamp-plugin.map iterative-chroma/chroma-excerpt.ttl iterative-chroma/chromacompare.sh iterative-match/match-cost.ttl iterative-match/matchcompare.sh spectrum-compare-plugin/Makefile.inc spectrum-compare-plugin/Makefile.linux spectrum-compare-plugin/Makefile.mingw32 spectrum-compare-plugin/Makefile.osx spectrum-compare-plugin/TuningDifference.cpp spectrum-compare-plugin/TuningDifference.h spectrum-compare-plugin/plugins.cpp spectrum-compare-plugin/vamp-plugin.list spectrum-compare-plugin/vamp-plugin.map src/TuningDifference.cpp src/TuningDifference.h src/plugins.cpp tuning-and-key/keycompare.sh tuning-and-key/keydetector.ttl vamp-plugin.list vamp-plugin.map
diffstat 37 files changed, 1018 insertions(+), 1634 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgsub	Thu Feb 05 10:13:31 2015 +0000
@@ -0,0 +1,1 @@
+constant-q-cpp = https://code.soundsoftware.ac.uk/hg/constant-q-cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgsubstate	Thu Feb 05 10:13:31 2015 +0000
@@ -0,0 +1,1 @@
+25ff58cc00be316d9a32e232a78a00e9374e0433 constant-q-cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/COPYING	Thu Feb 05 10:13:31 2015 +0000
@@ -0,0 +1,280 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile.inc	Thu Feb 05 10:13:31 2015 +0000
@@ -0,0 +1,60 @@
+
+# Edit this to the base name of your plugin library
+#
+PLUGIN_LIBRARY_NAME := tuning-difference
+
+# Edit this to list the .cpp or .c files in your plugin project
+#
+PLUGIN_SOURCES := src/TuningDifference.cpp src/plugins.cpp
+
+# Edit this to list the .h files in your plugin project
+#
+PLUGIN_HEADERS := src/TuningDifference.h
+
+
+##  Normally you should not edit anything below this line
+
+SRC_DIR		:= .
+
+CFLAGS		:= $(ARCHFLAGS) $(CFLAGS)
+CXXFLAGS	:= $(CFLAGS) -I. -I$(VAMPSDK_DIR) -Iconstant-q-cpp $(CXXFLAGS)
+
+LDFLAGS		:= $(ARCHFLAGS) $(LDFLAGS) -Lconstant-q-cpp -lcq
+PLUGIN_LDFLAGS	:= $(LDFLAGS) $(PLUGIN_LDFLAGS)
+
+# Defaults, overridden from the platform-specific Makefile
+VAMPSDK_DIR	?= ../vamp-plugin-sdk
+PLUGIN_EXT	?= .so
+CXX 		?= g++
+CC 		?= gcc
+
+PLUGIN 		:= $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT)
+
+PLUGIN_OBJECTS 	:= $(PLUGIN_SOURCES:.cpp=.o)
+PLUGIN_OBJECTS 	:= $(PLUGIN_OBJECTS:.c=.o)
+
+all: constant-q-cpp $(PLUGIN)
+
+.PHONY: constant-q-cpp
+constant-q-cpp: 
+	$(MAKE) -C $@ -f Makefile$(MAKEFILE_EXT) libcq.a
+
+$(PLUGIN): $(PLUGIN_OBJECTS) 
+	   $(CXX) -o $@ $^ $(PLUGIN_LDFLAGS)
+
+$(PLUGIN_OBJECTS): $(PLUGIN_HEADERS)
+
+clean:
+	rm -f $(PLUGIN_OBJECTS)
+	$(MAKE) -C constant-q-cpp -f Makefile$(MAKEFILE_EXT) clean
+
+distclean:	clean
+	rm -f $(PLUGIN)
+
+depend:
+	makedepend -Y -fMakefile.inc $(PLUGIN_SOURCES) $(PLUGIN_HEADERS)
+
+# DO NOT DELETE
+
+src/TuningDifference.o: src/TuningDifference.h
+src/plugins.o: src/TuningDifference.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile.linux	Thu Feb 05 10:13:31 2015 +0000
@@ -0,0 +1,16 @@
+
+#CXXFLAGS	:= -Wall -Wextra -Werror -g -fPIC -std=c++11
+
+CXXFLAGS	:= -Wall -Wextra -Werror -O3 -msse -msse2 -mfpmath=sse -ftree-vectorize -fPIC -std=c++11
+
+VAMPSDK_DIR	:= ../vamp-plugin-sdk
+
+PLUGIN_LDFLAGS	:= -shared -Wl,-Bsymbolic -Wl,-z,defs -Wl,--version-script=vamp-plugin.map $(VAMPSDK_DIR)/libvamp-sdk.a
+
+PLUGIN_EXT	:= .so
+
+MAKEFILE_EXT  := .linux
+
+include Makefile.inc
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile.mingw32	Thu Feb 05 10:13:31 2015 +0000
@@ -0,0 +1,21 @@
+
+TOOLPREFIX     ?= 
+CXX		= $(TOOLPREFIX)g++
+CC		= $(TOOLPREFIX)gcc
+LD		= $(TOOLPREFIX)g++
+AR		= $(TOOLPREFIX)ar
+RANLIB		= $(TOOLPREFIX)ranlib
+
+#CFLAGS		:= -Wall -Wextra -g
+
+CFLAGS		:= -Wall -Wextra -O3 -ftree-vectorize
+
+VAMPSDK_DIR	:= ../vamp-plugin-sdk
+
+PLUGIN_LDFLAGS	:= -shared -static -Wl,--retain-symbols-file=vamp-plugin.list $(VAMPSDK_DIR)/libvamp-sdk.a
+
+PLUGIN_EXT	:= .dll
+
+MAKEFILE_EXT  := .mingw32
+
+include Makefile.inc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile.osx	Thu Feb 05 10:13:31 2015 +0000
@@ -0,0 +1,18 @@
+
+#CFLAGS		:= -Wall -Wextra -g -fPIC
+
+CFLAGS		:= -Wall -Wextra -O3 -ftree-vectorize -fPIC
+
+ARCHFLAGS	?= -mmacosx-version-min=10.6 -arch x86_64 -arch i386
+
+VAMPSDK_DIR	:= ../vamp-plugin-sdk
+
+PLUGIN_LDFLAGS	:= -dynamiclib -exported_symbols_list vamp-plugin.list $(VAMPSDK_DIR)/libvamp-sdk.a
+
+PLUGIN_EXT	:= .dylib
+
+MAKEFILE_EXT  := .osx
+
+include Makefile.inc
+
+
--- a/README	Thu Feb 05 09:52:28 2015 +0000
+++ b/README	Thu Feb 05 10:13:31 2015 +0000
@@ -1,4 +1,20 @@
 
-The successful attempt is in chroma-compare-plugin. It's very slow,
-will be working on that.
+Plugin to calculate comparative tuning of recordings
+----------------------------------------------------
 
+This plugin estimates the tuning frequency (concert-A) of a recording,
+by comparing it with a "reference" recording of the same music that
+has a known tuning frequency. The aim is to identify the tuning
+frequency of the unknown recording even in difficult cases, such as
+where A is tuned more than a semitone below 440Hz.
+
+The reference recording could be another performance at known pitch
+or, for example, a MIDI rendering at 440Hz. The two recordings must be
+in the same key.
+
+The plugin expects to receive the two recordings of the same piece of
+music as its two channels of input. (You can provide these using the
+--multiplex option in Sonic Annotator, for example.) If you just feed
+it a single piece of music, it will probably estimate that it has the
+same tuning frequency as itself!
+
--- a/chroma-compare-plugin/Makefile.inc	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-
-# Edit this to the base name of your plugin library
-#
-PLUGIN_LIBRARY_NAME := tuning-difference
-
-# Edit this to list the .cpp or .c files in your plugin project
-#
-PLUGIN_SOURCES := TuningDifference.cpp plugins.cpp
-
-# Edit this to list the .h files in your plugin project
-#
-PLUGIN_HEADERS := TuningDifference.h
-
-
-##  Normally you should not edit anything below this line
-
-SRC_DIR		:= .
-
-CFLAGS		:= $(ARCHFLAGS) $(CFLAGS)
-CXXFLAGS	:= $(CFLAGS) -I. -I$(VAMPSDK_DIR) -I../../constant-q-cpp $(CXXFLAGS)
-
-LDFLAGS		:= $(ARCHFLAGS) $(LDFLAGS) -L../../constant-q-cpp -lcq
-PLUGIN_LDFLAGS	:= $(LDFLAGS) $(PLUGIN_LDFLAGS)
-
-# Defaults, overridden from the platform-specific Makefile
-VAMPSDK_DIR	?= ../vamp-plugin-sdk
-PLUGIN_EXT	?= .so
-CXX 		?= g++
-CC 		?= gcc
-
-PLUGIN 		:= $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT)
-
-PLUGIN_OBJECTS 	:= $(PLUGIN_SOURCES:.cpp=.o)
-PLUGIN_OBJECTS 	:= $(PLUGIN_OBJECTS:.c=.o)
-
-$(PLUGIN): $(PLUGIN_OBJECTS) 
-	   $(CXX) -o $@ $^ $(PLUGIN_LDFLAGS)
-
-$(PLUGIN_OBJECTS): $(PLUGIN_HEADERS)
-
-clean:
-	rm -f $(PLUGIN_OBJECTS)
-
-distclean:	clean
-	rm -f $(PLUGIN)
-
-depend:
-	makedepend -Y -fMakefile.inc $(PLUGIN_SOURCES) $(PLUGIN_HEADERS)
-
-# DO NOT DELETE
-
-TuningDifference.o: TuningDifference.h
-plugins.o: TuningDifference.h
--- a/chroma-compare-plugin/Makefile.linux	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-
-# For a debug build...
-
-#CXXFLAGS	:= -Wall -Wextra -Werror -g -fPIC -std=c++11
-
-# ... or for a release build
-
-CXXFLAGS	:= -Wall -Wextra -Werror -O3 -msse -msse2 -mfpmath=sse -ftree-vectorize -fPIC -std=c++11
-
-
-# Location of Vamp plugin SDK relative to the project directory
-
-VAMPSDK_DIR	:= ../../vamp-plugin-sdk
-
-
-# Libraries and linker flags required by plugin: add any -l<library>
-# options here
-
-PLUGIN_LDFLAGS	:= -shared -Wl,-Bsymbolic -Wl,-z,defs -Wl,--version-script=vamp-plugin.map $(VAMPSDK_DIR)/libvamp-sdk.a
-
-
-# File extension for plugin library on this platform
-
-PLUGIN_EXT	:= .so
-
-
-include Makefile.inc
-
-
--- a/chroma-compare-plugin/Makefile.mingw32	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-
-##  Makefile for Vamp plugin using MinGW tools on Windows.
-##
-##  Edit this to adjust compiler and library settings when
-##  building using MinGW.
-##
-##  Note that the list of source files, etc, goes in Makefile.inc
-##  instead so that it can be included by all platform Makefiles.
-
-TOOLPREFIX     ?= 
-CXX		= $(TOOLPREFIX)g++
-CC		= $(TOOLPREFIX)gcc
-LD		= $(TOOLPREFIX)g++
-AR		= $(TOOLPREFIX)ar
-RANLIB		= $(TOOLPREFIX)ranlib
-
-
-# For a debug build...
-
-CFLAGS		:= -Wall -Wextra -g
-
-# ... or for a release build
-
-#CFLAGS		:= -Wall -Wextra -O3 -ftree-vectorize
-
-
-# Location of Vamp plugin SDK relative to the project directory
-
-VAMPSDK_DIR	:= ../vamp-plugin-sdk
-
-
-# Libraries and linker flags required by plugin: add any -l<library>
-# options here
-
-PLUGIN_LDFLAGS	:= -shared -static -Wl,--retain-symbols-file=vamp-plugin.list $(VAMPSDK_DIR)/libvamp-sdk.a
-
-
-# File extension for plugin library on this platform
-
-PLUGIN_EXT	:= .dll
-
-
-include Makefile.inc
--- a/chroma-compare-plugin/Makefile.osx	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-
-##  Makefile for Vamp plugin using command-line tools on OS/X.
-##
-##  Edit this to adjust compiler and library settings when
-##  building for OS/X.
-##
-##  Note that the list of source files, etc, goes in Makefile.inc
-##  instead so that it can be included by all platform Makefiles.
-
-
-# For a debug build...
-
-CFLAGS		:= -Wall -Wextra -g -fPIC
-
-# ... or for a release build
-
-#CFLAGS		:= -Wall -Wextra -O3 -ftree-vectorize -fPIC
-
-
-# Flags to determine processor architecture and system SDK
-
-ARCHFLAGS	?= -mmacosx-version-min=10.6 -arch x86_64 -arch i386
-
-
-# Location of Vamp plugin SDK relative to the project directory
-
-VAMPSDK_DIR	:= ../vamp-plugin-sdk
-
-
-# Libraries and linker flags required by plugin: add any -l<library>
-# options here
-
-PLUGIN_LDFLAGS	:= -dynamiclib -exported_symbols_list vamp-plugin.list $(VAMPSDK_DIR)/libvamp-sdk.a
-
-
-# File extension for plugin library on this platform
-
-PLUGIN_EXT	:= .dylib
-
-
-include Makefile.inc
-
-
--- a/chroma-compare-plugin/TuningDifference.cpp	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,481 +0,0 @@
-
-#include "TuningDifference.h"
-
-#include <iostream>
-
-#include <cmath>
-#include <cstdio>
-
-#include <algorithm>
-
-using namespace std;
-
-static double pitchToFrequency(int pitch,
-			       double centsOffset = 0.,
-			       double concertA = 440.)
-{
-    double p = double(pitch) + (centsOffset / 100.);
-    return concertA * pow(2.0, (p - 69.0) / 12.0); 
-}
-
-static double frequencyForCentsAbove440(double cents)
-{
-    return pitchToFrequency(69, cents, 440.);
-}
-
-TuningDifference::TuningDifference(float inputSampleRate) :
-    Plugin(inputSampleRate),
-    m_bpo(60),
-    m_refChroma(new Chromagram(paramsForTuningFrequency(440.))),
-    m_blockSize(0),
-    m_frameCount(0)
-{
-}
-
-TuningDifference::~TuningDifference()
-{
-}
-
-string
-TuningDifference::getIdentifier() const
-{
-    return "tuning-difference";
-}
-
-string
-TuningDifference::getName() const
-{
-    return "Tuning Difference";
-}
-
-string
-TuningDifference::getDescription() const
-{
-    // Return something helpful here!
-    return "";
-}
-
-string
-TuningDifference::getMaker() const
-{
-    // Your name here
-    return "";
-}
-
-int
-TuningDifference::getPluginVersion() const
-{
-    // Increment this each time you release a version that behaves
-    // differently from the previous one
-    return 1;
-}
-
-string
-TuningDifference::getCopyright() const
-{
-    // This function is not ideally named.  It does not necessarily
-    // need to say who made the plugin -- getMaker does that -- but it
-    // should indicate the terms under which it is distributed.  For
-    // example, "Copyright (year). All Rights Reserved", or "GPL"
-    return "";
-}
-
-TuningDifference::InputDomain
-TuningDifference::getInputDomain() const
-{
-    return TimeDomain;
-}
-
-size_t
-TuningDifference::getPreferredBlockSize() const
-{
-    return 0;
-}
-
-size_t 
-TuningDifference::getPreferredStepSize() const
-{
-    return 0;
-}
-
-size_t
-TuningDifference::getMinChannelCount() const
-{
-    return 2;
-}
-
-size_t
-TuningDifference::getMaxChannelCount() const
-{
-    return 2;
-}
-
-TuningDifference::ParameterList
-TuningDifference::getParameterDescriptors() const
-{
-    ParameterList list;
-    //!!! parameter: max search range
-    //!!! parameter: fine search precision
-    return list;
-}
-
-float
-TuningDifference::getParameter(string) const
-{
-    return 0;
-}
-
-void
-TuningDifference::setParameter(string, float) 
-{
-}
-
-TuningDifference::ProgramList
-TuningDifference::getPrograms() const
-{
-    ProgramList list;
-    return list;
-}
-
-string
-TuningDifference::getCurrentProgram() const
-{
-    return ""; // no programs
-}
-
-void
-TuningDifference::selectProgram(string)
-{
-}
-
-TuningDifference::OutputList
-TuningDifference::getOutputDescriptors() const
-{
-    OutputList list;
-
-    OutputDescriptor d;
-    d.identifier = "cents";
-    d.name = "Tuning Difference";
-    d.description = "Difference in averaged frequency profile between channels 1 and 2, in cents. A positive value means channel 2 is higher.";
-    d.unit = "cents";
-    d.hasFixedBinCount = true;
-    d.binCount = 1;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::VariableSampleRate;
-    d.hasDuration = false;
-    m_outputs[d.identifier] = list.size();
-    list.push_back(d);
-
-    d.identifier = "tuningfreq";
-    d.name = "Relative Tuning Frequency";
-    d.description = "Tuning frequency of channel 2, if channel 1 is assumed to contain the same music as it at a tuning frequency of A=440Hz.";
-    d.unit = "hz";
-    d.hasFixedBinCount = true;
-    d.binCount = 1;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::VariableSampleRate;
-    d.hasDuration = false;
-    m_outputs[d.identifier] = list.size();
-    list.push_back(d);
-
-    d.identifier = "reffeature";
-    d.name = "Reference Feature";
-    d.description = "Chroma feature from reference audio.";
-    d.unit = "";
-    d.hasFixedBinCount = true;
-    d.binCount = m_bpo;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::FixedSampleRate;
-    d.sampleRate = 1;
-    d.hasDuration = false;
-    m_outputs[d.identifier] = list.size();
-    list.push_back(d);
-
-    d.identifier = "otherfeature";
-    d.name = "Other Feature";
-    d.description = "Chroma feature from other audio, before rotation.";
-    d.unit = "";
-    d.hasFixedBinCount = true;
-    d.binCount = m_bpo;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::FixedSampleRate;
-    d.sampleRate = 1;
-    d.hasDuration = false;
-    m_outputs[d.identifier] = list.size();
-    list.push_back(d);
-
-    d.identifier = "rotfeature";
-    d.name = "Other Feature at Rotated Frequency";
-    d.description = "Chroma feature from reference audio calculated with the tuning frequency obtained from rotation matching.";
-    d.unit = "";
-    d.hasFixedBinCount = true;
-    d.binCount = m_bpo;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::FixedSampleRate;
-    d.sampleRate = 1;
-    d.hasDuration = false;
-    m_outputs[d.identifier] = list.size();
-    list.push_back(d);
-
-    return list;
-}
-
-bool
-TuningDifference::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    if (channels < getMinChannelCount() ||
-	channels > getMaxChannelCount()) return false;
-
-    if (stepSize != blockSize) return false;
-
-    m_blockSize = blockSize;
-
-    reset();
-    
-    return true;
-}
-
-void
-TuningDifference::reset()
-{
-    if (m_frameCount > 0) {
-	m_refChroma.reset(new Chromagram(paramsForTuningFrequency(440.)));
-	m_frameCount = 0;
-    }
-    m_refTotals = TFeature(m_bpo, 0.0);
-    m_other.clear();
-}
-
-template<typename T>
-void addTo(vector<T> &a, const vector<T> &b)
-{
-    transform(a.begin(), a.end(), b.begin(), a.begin(), plus<T>());
-}
-
-template<typename T>
-T distance(const vector<T> &a, const vector<T> &b)
-{
-    return inner_product(a.begin(), a.end(), b.begin(), T(),
-			 plus<T>(), [](T x, T y) { return fabs(x - y); });
-}
-
-TuningDifference::TFeature
-TuningDifference::computeFeatureFromTotals(const TFeature &totals) const
-{
-    if (m_frameCount == 0) return totals;
-    
-    TFeature feature(m_bpo);
-    double sum = 0.0;
-
-    for (int i = 0; i < m_bpo; ++i) {
-	double value = totals[i] / m_frameCount;
-	feature[i] += value;
-	sum += value;
-    }
-
-    for (int i = 0; i < m_bpo; ++i) {
-	feature[i] /= sum;
-    }
-
-    cerr << "computeFeatureFromTotals: feature values:" << endl;
-    for (auto v: feature) cerr << v << " ";
-    cerr << endl;
-    
-    return feature;
-}
-
-Chromagram::Parameters
-TuningDifference::paramsForTuningFrequency(double hz) const
-{
-    Chromagram::Parameters params(m_inputSampleRate);
-    params.lowestOctave = 0;
-    params.octaveCount = 6;
-    params.binsPerOctave = m_bpo;
-    params.tuningFrequency = hz;
-    params.atomHopFactor = 0.5;
-    return params;
-}
-
-TuningDifference::TFeature
-TuningDifference::computeFeatureFromSignal(const Signal &signal, double hz) const
-{
-    Chromagram chromagram(paramsForTuningFrequency(hz));
-
-    TFeature totals(m_bpo, 0.0);
-
-    cerr << "computeFeatureFromSignal: hz = " << hz << ", frame count = " << m_frameCount << endl;
-    
-    for (int i = 0; i < m_frameCount; ++i) {
-	Signal::const_iterator first = signal.begin() + i * m_blockSize;
-	Signal::const_iterator last = first + m_blockSize;
-	if (last > signal.end()) last = signal.end();
-	CQBase::RealSequence input(first, last);
-	input.resize(m_blockSize);
-	CQBase::RealBlock block = chromagram.process(input);
-	for (const auto &v: block) addTo(totals, v);
-    }
-
-    return computeFeatureFromTotals(totals);
-}
-
-TuningDifference::FeatureSet
-TuningDifference::process(const float *const *inputBuffers, Vamp::RealTime)
-{
-    CQBase::RealBlock block;
-    CQBase::RealSequence input;
-
-    input = CQBase::RealSequence
-	(inputBuffers[0], inputBuffers[0] + m_blockSize);
-    block = m_refChroma->process(input);
-    for (const auto &v: block) addTo(m_refTotals, v);
-
-    m_other.insert(m_other.end(),
-		   inputBuffers[1], inputBuffers[1] + m_blockSize);
-    
-    ++m_frameCount;
-    return FeatureSet();
-}
-
-double
-TuningDifference::featureDistance(const TFeature &other, int rotation) const
-{
-    if (rotation == 0) {
-	return distance(m_refFeature, other);
-    } else {
-	// A positive rotation pushes the tuning frequency up for this
-	// chroma, negative one pulls it down. If a positive rotation
-	// makes this chroma match an un-rotated reference, then this
-	// chroma must have initially been lower than the reference.
-	TFeature r(other);
-	if (rotation < 0) {
-	    rotate(r.begin(), r.begin() - rotation, r.end());
-	} else {
-	    rotate(r.begin(), r.end() - rotation, r.end());
-	}
-	return distance(m_refFeature, r);
-    }
-}
-
-int
-TuningDifference::findBestRotation(const TFeature &other) const
-{
-    map<double, int> dists;
-
-    int maxSemis = 6;
-    int maxRotation = (m_bpo * maxSemis) / 12;
-
-    for (int r = -maxRotation; r <= maxRotation; ++r) {
-	double dist = featureDistance(other, r);
-	dists[dist] = r;
-	cerr << "rotation " << r << ": score " << dist << endl;
-    }
-
-    int best = dists.begin()->second;
-
-    cerr << "best is " << best << endl;
-    return best;
-}
-
-pair<int, double>
-TuningDifference::findFineFrequency(int coarseCents, double coarseScore)
-{
-    int coarseResolution = 1200 / m_bpo;
-    int searchDistance = coarseResolution/2 - 1;
-
-    double bestScore = coarseScore;
-    int bestCents = coarseCents;
-    double bestHz = frequencyForCentsAbove440(coarseCents);
-
-    cerr << "corresponding coarse Hz " << bestHz << " scores " << coarseScore << endl;
-    cerr << "searchDistance = " << searchDistance << endl;
-    
-    for (int sign = -1; sign <= 1; sign += 2) {
-	for (int offset = 1; offset <= searchDistance; ++offset) {
-
-	    int fineCents = coarseCents + sign * offset;
-
-	    cerr << "trying with fineCents = " << fineCents << "..." << endl;
-	    
-	    double fineHz = frequencyForCentsAbove440(fineCents);
-	    TFeature fineFeature = computeFeatureFromSignal(m_other, fineHz);
-	    double fineScore = featureDistance(fineFeature);
-
-	    cerr << "fine offset = " << offset << ", cents = " << fineCents
-		 << ", Hz = " << fineHz << ", score " << fineScore
-		 << " (best score so far " << bestScore << ")" << endl;
-	    
-	    if (fineScore < bestScore) {
-		cerr << "is good!" << endl;
-		bestScore = fineScore;
-		bestCents = fineCents;
-		bestHz = fineHz;
-	    } else {
-		break;
-	    }
-	}
-    }
-
-    //!!! could keep a vector of scores & then interpolate...
-    
-    return pair<int, double>(bestCents, bestHz);
-}
-
-TuningDifference::FeatureSet
-TuningDifference::getRemainingFeatures()
-{
-    FeatureSet fs;
-    if (m_frameCount == 0) return fs;
-
-    m_refFeature = computeFeatureFromTotals(m_refTotals);
-    TFeature otherFeature = computeFeatureFromSignal(m_other, 440.);
-
-    Feature f;
-
-    f.values.clear();
-    for (auto v: m_refFeature) f.values.push_back(v);
-    fs[m_outputs["reffeature"]].push_back(f);
-
-    f.values.clear();
-    for (auto v: otherFeature) f.values.push_back(v);
-    fs[m_outputs["otherfeature"]].push_back(f); 
-   
-    int rotation = findBestRotation(otherFeature);
-
-    int coarseCents = -(rotation * 1200) / m_bpo;
-
-    cerr << "rotation " << rotation << " -> cents " << coarseCents << endl;
-
-    double coarseHz = frequencyForCentsAbove440(coarseCents);
-
-    TFeature coarseFeature = computeFeatureFromSignal(m_other, coarseHz);
-    double coarseScore = featureDistance(coarseFeature);
-
-    cerr << "corresponding Hz " << coarseHz << " scores " << coarseScore << endl;
-
-    //!!! This should be returning the fine chroma, not the coarse
-    f.values.clear();
-    for (auto v: coarseFeature) f.values.push_back(v);
-    fs[m_outputs["rotfeature"]].push_back(f);
-
-    pair<int, double> fine = findFineFrequency(coarseCents, coarseScore);
-    int fineCents = fine.first;
-    double fineHz = fine.second;
-
-    f.values.clear();
-    f.values.push_back(fineHz);
-    fs[m_outputs["tuningfreq"]].push_back(f);
-
-    f.values.clear();
-    f.values.push_back(fineCents);
-    fs[m_outputs["cents"]].push_back(f);
-    
-    cerr << "overall best Hz = " << fineHz << endl;
-    
-    return fs;
-}
-
--- a/chroma-compare-plugin/TuningDifference.h	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-#ifndef TUNING_DIFFERENCE_H
-#define TUNING_DIFFERENCE_H
-
-#include <vamp-sdk/Plugin.h>
-
-#include <cq/Chromagram.h>
-
-#include <memory>
-
-using std::string;
-using std::vector;
-
-class TuningDifference : public Vamp::Plugin
-{
-public:
-    TuningDifference(float inputSampleRate);
-    virtual ~TuningDifference();
-
-    string getIdentifier() const;
-    string getName() const;
-    string getDescription() const;
-    string getMaker() const;
-    int getPluginVersion() const;
-    string getCopyright() const;
-
-    InputDomain getInputDomain() const;
-    size_t getPreferredBlockSize() const;
-    size_t getPreferredStepSize() const;
-    size_t getMinChannelCount() const;
-    size_t getMaxChannelCount() const;
-
-    ParameterList getParameterDescriptors() const;
-    float getParameter(string identifier) const;
-    void setParameter(string identifier, float value);
-
-    ProgramList getPrograms() const;
-    string getCurrentProgram() const;
-    void selectProgram(string name);
-
-    OutputList getOutputDescriptors() const;
-
-    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
-    void reset();
-
-    FeatureSet process(const float *const *inputBuffers,
-                       Vamp::RealTime timestamp);
-
-    FeatureSet getRemainingFeatures();
-
-protected:
-    typedef vector<float> Signal;
-    typedef vector<double> TFeature;
-
-    int m_bpo;
-    std::unique_ptr<Chromagram> m_refChroma;
-    TFeature m_refTotals;
-    TFeature m_refFeature;
-    Signal m_other;
-    int m_blockSize;
-    int m_frameCount;
-
-    Chromagram::Parameters paramsForTuningFrequency(double hz) const;
-    TFeature computeFeatureFromTotals(const TFeature &totals) const;
-    TFeature computeFeatureFromSignal(const Signal &signal, double hz) const;
-    double featureDistance(const TFeature &other, int rotation = 0) const;
-    int findBestRotation(const TFeature &other) const;
-    std::pair<int, double> findFineFrequency(int coarseCents, double coarseScore);
-
-    mutable std::map<string, int> m_outputs;
-};
-
-
-#endif
--- a/chroma-compare-plugin/plugins.cpp	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-
-#include <vamp/vamp.h>
-#include <vamp-sdk/PluginAdapter.h>
-
-#include "TuningDifference.h"
-
-static Vamp::PluginAdapter<TuningDifference> tdAdapter;
-
-
-const VampPluginDescriptor *
-vampGetPluginDescriptor(unsigned int version, unsigned int index)
-{
-    if (version < 1) return 0;
-
-    switch (index) {
-    case  0: return tdAdapter.getDescriptor();
-    default: return 0;
-    }
-}
-
-
--- a/chroma-compare-plugin/vamp-plugin.list	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-_vampGetPluginDescriptor
--- a/chroma-compare-plugin/vamp-plugin.map	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-{
-	global: vampGetPluginDescriptor;
-	local: *;
-};
--- a/iterative-chroma/chroma-excerpt.ttl	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-@prefix xsd:      <http://www.w3.org/2001/XMLSchema#> .
-@prefix vamp:     <http://purl.org/ontology/vamp/> .
-@prefix :         <#> .
-
-:transform a vamp:Transform ;
-    vamp:plugin <http://vamp-plugins.org/rdf/plugins/qm-vamp-plugins#qm-chromagram> ;
-    vamp:duration "PT30S"^^xsd:duration ;
-    vamp:parameter_binding [
-        vamp:parameter [ vamp:identifier "bpo" ] ;
-        vamp:value "60"^^xsd:float ;
-    ] ;
-    vamp:parameter_binding [
-        vamp:parameter [ vamp:identifier "tuning" ] ;
-        vamp:value "440"^^xsd:float ;
-    ] ;
-    vamp:parameter_binding [
-        vamp:parameter [ vamp:identifier "normalization" ] ;
-        vamp:value "1"^^xsd:float ;  # unit sum
-    ] ;
-    vamp:output <http://vamp-plugins.org/rdf/plugins/qm-vamp-plugins#qm-chromagram_output_chromagram> .
--- a/iterative-chroma/chromacompare.sh	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-#!/bin/bash
-
-set -e
-
-mypath=`dirname $0`
-
-sonic-annotator --minversion 1.1 || exit 1
-
-reference="$1"
-other="$2"
-
-usage() {
-    echo "Usage: $0 reference.wav other.wav" 1>&2
-    exit 2
-}
-
-test -n "$reference" || usage
-test -n "$other" || usage
-
-if ! test -f "$reference" ; then
-    echo "Reference file $reference not found" 1>&2
-    exit 1
-fi
-
-if ! test -f "$other" ; then
-    echo "Other file $other not found" 1>&2
-    exit 1
-fi
-
-refchroma="/tmp/$$.ref"
-otherchroma="/tmp/$$.other"
-tmpscript="/tmp/$$.dc"
-transform="/tmp/$$.ttl"
-scores="/tmp/$$.scores.txt"
-trap "rm $refchroma $otherchroma $tmpscript $transform $scores" 0
-
-extract() {
-    hz="$1"
-    file="$2"
-    cat chroma-excerpt.ttl | sed 's,"440","'"$hz"'",' > "$transform"
-    sonic-annotator -t "$transform" --summary mean --summary-only -w csv --csv-stdout --csv-omit-filename "$file" 2>/dev/null | cut -d, -f4-63 | sed 's/,/\n/g'
-}
-
-extract 440 "$reference" | cat -n > "$refchroma"
-
-sox "$other" -r 44100 -c 1 b.wav
-
-for cents in $(seq -400 10 400) ; do
-
-    hz=$(perl -e "print 440.0 * (2.0 ** ($cents / 1200.0))")
-
-    extract "$hz" b.wav | cat -n > "$otherchroma"
-    (
-	echo "6 k 0"
-	join "$refchroma" "$otherchroma" | \
-	    awk '{ print $2, $3, "- d * +" }' # square difference
-	echo "p"
-    ) > "$tmpscript"
-
-    dist=$( cat "$tmpscript" | dc )
-    echo "$dist $hz"
-    
-done | tee "$scores"
-
-echo
-echo Scores:
-sort -n "$scores"
-
-echo
-bestfreq=$(sort -n "$scores" | head -1 | awk '{ print $2; }')
-echo "I reckon the tuning frequency is $bestfreq"
-
-
--- a/iterative-match/match-cost.ttl	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-@prefix xsd:      <http://www.w3.org/2001/XMLSchema#> .
-@prefix vamp:     <http://purl.org/ontology/vamp/> .
-@prefix :         <#> .
-
-:param_chroma
-    vamp:parameter [ vamp:identifier "usechroma" ] ;
-    vamp:value "1"^^xsd:float .
-
-:param_freq
-    vamp:parameter [ vamp:identifier "freq2" ] ;
-    vamp:value "440"^^xsd:float .
-
-:transform_a a vamp:Transform ;
-    vamp:plugin <http://vamp-plugins.org/rdf/plugins/match-vamp-plugin#match> ;
-    vamp:plugin_version "3"^^xsd:int ;
-    vamp:step_size "882"^^xsd:int ; 
-    vamp:block_size "2048"^^xsd:int ; 
-    vamp:sample_rate "44100"^^xsd:int ;
-    vamp:parameter_binding :param_chroma ;
-    vamp:parameter_binding :param_freq ;
-    vamp:output [ vamp:identifier "overall_cost" ] .
-
--- a/iterative-match/matchcompare.sh	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-#!/bin/bash
-
-set -e
-
-mypath=`dirname $0`
-
-sonic-annotator --minversion 1.1 || exit 1
-
-reference="$1"
-other="$2"
-
-usage() {
-    echo "Usage: $0 reference.wav other.wav" 1>&2
-    exit 2
-}
-
-test -n "$reference" || usage
-test -n "$other" || usage
-
-set -u
-
-transform="/tmp/$$.ttl"
-scores="/tmp/$$.scores.txt"
-trap "rm $transform $scores" 0
-
-#export VAMP_PATH="$mypath"/../match-vamp
-
-sox "$reference" -r 44100 -c 1 a.wav
-sox "$other" -r 44100 -c 1 b.wav
-
-for cents in $(seq -400 10 400) ; do
-
-    freq=$(perl -e "print 440.0 * (2.0 ** ($cents / 1200.0))")
-
-    cat match-cost.ttl | sed "s,440,$freq," > "$transform"
-
-    score=$(sonic-annotator -t "$transform" --multiplex -w csv --csv-stdout a.wav b.wav | awk -F, '{ print $3 }')
-
-    echo "$score $freq"
-    
-done | tee "$scores"
-
-echo
-echo Scores:
-sort -n "$scores"
-
-echo
-bestfreq=$(sort -n "$scores" | head -1 | awk '{ print $2; }')
-echo "I reckon the tuning frequency is $bestfreq"
-
--- a/spectrum-compare-plugin/Makefile.inc	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-
-##  Makefile for Vamp plugin builds using command-line tools.
-##
-##  This file defines all of the system-independent information about
-##  your project: the list of source files, plugin library name, etc.
-##  Edit this file to make sure it has all the right information.
-##
-##  This file does not define the system-specific stuff such as which
-##  compiler to use -- that goes into Makefile.osx, Makefile.mingw32,
-##  Makefile.linux etc.  Those files all include this file, so that
-##  they all have a consistent set of project data.
-##
-##  To build the plugin project, type
-##
-##    $ gmake -f Makefile.osx
-##
-##  or whatever the equivalent filename suffix is for your platform.
-##
-##  This requires GNU make, which is what you get with OS/X, Linux, or
-##  MinGW/Cygwin on Windows.
-##
-##  (For Windows builds using MS Visual Studio, start instead with the
-##  VampExamplePlugins project found in the build directory of the SDK.)
-
-
-# Edit this to the base name of your plugin library
-#
-PLUGIN_LIBRARY_NAME := tuning-difference
-
-# Edit this to list the .cpp or .c files in your plugin project
-#
-PLUGIN_SOURCES := TuningDifference.cpp plugins.cpp
-
-# Edit this to list the .h files in your plugin project
-#
-PLUGIN_HEADERS := TuningDifference.h
-
-
-##  Normally you should not edit anything below this line
-
-SRC_DIR		:= .
-
-CFLAGS		:= $(ARCHFLAGS) $(CFLAGS)
-CXXFLAGS	:= $(CFLAGS) -I. -I$(VAMPSDK_DIR) $(CXXFLAGS)
-
-LDFLAGS		:= $(ARCHFLAGS) $(LDFLAGS) 
-PLUGIN_LDFLAGS	:= $(LDFLAGS) $(PLUGIN_LDFLAGS)
-
-# Defaults, overridden from the platform-specific Makefile
-VAMPSDK_DIR	?= ../vamp-plugin-sdk
-PLUGIN_EXT	?= .so
-CXX 		?= g++
-CC 		?= gcc
-
-PLUGIN 		:= $(PLUGIN_LIBRARY_NAME)$(PLUGIN_EXT)
-
-PLUGIN_OBJECTS 	:= $(PLUGIN_SOURCES:.cpp=.o)
-PLUGIN_OBJECTS 	:= $(PLUGIN_OBJECTS:.c=.o)
-
-$(PLUGIN): $(PLUGIN_OBJECTS) 
-	   $(CXX) -o $@ $^ $(PLUGIN_LDFLAGS)
-
-$(PLUGIN_OBJECTS): $(PLUGIN_HEADERS)
-
-clean:
-	rm -f $(PLUGIN_OBJECTS)
-
-distclean:	clean
-	rm -f $(PLUGIN)
-
-depend:
-	makedepend -Y -fMakefile.inc $(PLUGIN_SOURCES) $(PLUGIN_HEADERS)
-
-# DO NOT DELETE
-
-TuningDifference.o: TuningDifference.h
-plugins.o: TuningDifference.h
--- a/spectrum-compare-plugin/Makefile.linux	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-
-##  Makefile for Vamp plugin using GNU tools on Linux.
-##
-##  Edit this to adjust compiler and library settings when
-##  building for Linux.
-##
-##  Note that the list of source files, etc, goes in Makefile.inc
-##  instead so that it can be included by all platform Makefiles.
-
-
-# For a debug build...
-
-CFLAGS		:= -Wall -Wextra -g -fPIC
-
-# ... or for a release build
-
-#CFLAGS		:= -Wall -Wextra -O3 -msse -msse2 -mfpmath=sse -ftree-vectorize -fPIC
-
-
-# Location of Vamp plugin SDK relative to the project directory
-
-VAMPSDK_DIR	:= ../vamp-plugin-sdk
-
-
-# Libraries and linker flags required by plugin: add any -l<library>
-# options here
-
-PLUGIN_LDFLAGS	:= -shared -Wl,-Bsymbolic -Wl,-z,defs -Wl,--version-script=vamp-plugin.map $(VAMPSDK_DIR)/libvamp-sdk.a
-
-
-# File extension for plugin library on this platform
-
-PLUGIN_EXT	:= .so
-
-
-include Makefile.inc
-
-
--- a/spectrum-compare-plugin/Makefile.mingw32	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-
-##  Makefile for Vamp plugin using MinGW tools on Windows.
-##
-##  Edit this to adjust compiler and library settings when
-##  building using MinGW.
-##
-##  Note that the list of source files, etc, goes in Makefile.inc
-##  instead so that it can be included by all platform Makefiles.
-
-TOOLPREFIX     ?= 
-CXX		= $(TOOLPREFIX)g++
-CC		= $(TOOLPREFIX)gcc
-LD		= $(TOOLPREFIX)g++
-AR		= $(TOOLPREFIX)ar
-RANLIB		= $(TOOLPREFIX)ranlib
-
-
-# For a debug build...
-
-CFLAGS		:= -Wall -Wextra -g
-
-# ... or for a release build
-
-#CFLAGS		:= -Wall -Wextra -O3 -ftree-vectorize
-
-
-# Location of Vamp plugin SDK relative to the project directory
-
-VAMPSDK_DIR	:= ../vamp-plugin-sdk
-
-
-# Libraries and linker flags required by plugin: add any -l<library>
-# options here
-
-PLUGIN_LDFLAGS	:= -shared -static -Wl,--retain-symbols-file=vamp-plugin.list $(VAMPSDK_DIR)/libvamp-sdk.a
-
-
-# File extension for plugin library on this platform
-
-PLUGIN_EXT	:= .dll
-
-
-include Makefile.inc
--- a/spectrum-compare-plugin/Makefile.osx	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-
-##  Makefile for Vamp plugin using command-line tools on OS/X.
-##
-##  Edit this to adjust compiler and library settings when
-##  building for OS/X.
-##
-##  Note that the list of source files, etc, goes in Makefile.inc
-##  instead so that it can be included by all platform Makefiles.
-
-
-# For a debug build...
-
-CFLAGS		:= -Wall -Wextra -g -fPIC
-
-# ... or for a release build
-
-#CFLAGS		:= -Wall -Wextra -O3 -ftree-vectorize -fPIC
-
-
-# Flags to determine processor architecture and system SDK
-
-ARCHFLAGS	?= -mmacosx-version-min=10.6 -arch x86_64 -arch i386
-
-
-# Location of Vamp plugin SDK relative to the project directory
-
-VAMPSDK_DIR	:= ../vamp-plugin-sdk
-
-
-# Libraries and linker flags required by plugin: add any -l<library>
-# options here
-
-PLUGIN_LDFLAGS	:= -dynamiclib -exported_symbols_list vamp-plugin.list $(VAMPSDK_DIR)/libvamp-sdk.a
-
-
-# File extension for plugin library on this platform
-
-PLUGIN_EXT	:= .dylib
-
-
-include Makefile.inc
-
-
--- a/spectrum-compare-plugin/TuningDifference.cpp	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,382 +0,0 @@
-
-#include "TuningDifference.h"
-
-#include <iostream>
-
-#include <cmath>
-#include <cstdio>
-
-using std::cerr;
-using std::endl;
-
-static double targetFmin = 60.0;
-static double targetFmax = 1500.0;
-
-TuningDifference::TuningDifference(float inputSampleRate) :
-    Plugin(inputSampleRate)
-{
-}
-
-TuningDifference::~TuningDifference()
-{
-}
-
-string
-TuningDifference::getIdentifier() const
-{
-    return "tuning-difference";
-}
-
-string
-TuningDifference::getName() const
-{
-    return "Tuning Difference";
-}
-
-string
-TuningDifference::getDescription() const
-{
-    // Return something helpful here!
-    return "";
-}
-
-string
-TuningDifference::getMaker() const
-{
-    // Your name here
-    return "";
-}
-
-int
-TuningDifference::getPluginVersion() const
-{
-    // Increment this each time you release a version that behaves
-    // differently from the previous one
-    return 1;
-}
-
-string
-TuningDifference::getCopyright() const
-{
-    // This function is not ideally named.  It does not necessarily
-    // need to say who made the plugin -- getMaker does that -- but it
-    // should indicate the terms under which it is distributed.  For
-    // example, "Copyright (year). All Rights Reserved", or "GPL"
-    return "";
-}
-
-TuningDifference::InputDomain
-TuningDifference::getInputDomain() const
-{
-    return FrequencyDomain;
-}
-
-size_t
-TuningDifference::getPreferredBlockSize() const
-{
-    return 16384;
-}
-
-size_t 
-TuningDifference::getPreferredStepSize() const
-{
-    return 0;
-}
-
-size_t
-TuningDifference::getMinChannelCount() const
-{
-    return 2;
-}
-
-size_t
-TuningDifference::getMaxChannelCount() const
-{
-    return 2;
-}
-
-TuningDifference::ParameterList
-TuningDifference::getParameterDescriptors() const
-{
-    ParameterList list;
-    return list;
-}
-
-float
-TuningDifference::getParameter(string) const
-{
-    return 0;
-}
-
-void
-TuningDifference::setParameter(string, float) 
-{
-}
-
-TuningDifference::ProgramList
-TuningDifference::getPrograms() const
-{
-    ProgramList list;
-    return list;
-}
-
-string
-TuningDifference::getCurrentProgram() const
-{
-    return ""; // no programs
-}
-
-void
-TuningDifference::selectProgram(string)
-{
-}
-
-TuningDifference::OutputList
-TuningDifference::getOutputDescriptors() const
-{
-    OutputList list;
-
-    OutputDescriptor d;
-    d.identifier = "cents";
-    d.name = "Tuning Difference";
-    d.description = "Difference in averaged frequency profile between channels 1 and 2, in cents. A positive value means channel 2 is higher.";
-    d.unit = "cents";
-    d.hasFixedBinCount = true;
-    d.binCount = 1;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::VariableSampleRate;
-    d.hasDuration = false;
-    list.push_back(d);
-
-    d.identifier = "tuningfreq";
-    d.name = "Relative Tuning Frequency";
-    d.description = "Tuning frequency of channel 2, if channel 1 is assumed to contain the same music as it at a tuning frequency of A=440Hz.";
-    d.unit = "hz";
-    d.hasFixedBinCount = true;
-    d.binCount = 1;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::VariableSampleRate;
-    d.hasDuration = false;
-    list.push_back(d);
-
-    d.identifier = "curve";
-    d.name = "Shift Correlation Curve";
-    d.description = "Correlation between shifted and unshifted sources, for each probed shift in cents.";
-    d.unit = "";
-    d.hasFixedBinCount = true;
-    d.binCount = 1;
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::FixedSampleRate;
-    d.sampleRate = 100;
-    d.hasDuration = false;
-    list.push_back(d);
-
-    int targetBinMin = int(floor(targetFmin * m_blockSize / m_inputSampleRate));
-    int targetBinMax = int(ceil(targetFmax * m_blockSize / m_inputSampleRate));
-    cerr << "target bin range: " << targetBinMin << " -> " << targetBinMax << endl;
-
-    d.identifier = "averages";
-    d.name = "Harmonic spectrum averages";
-    d.description = "Average of harmonic spectrum for each channel.";
-    d.unit = "";
-    d.hasFixedBinCount = true;
-    d.binCount = (targetBinMax > targetBinMin ? targetBinMax - targetBinMin + 1 : 100);
-    d.hasKnownExtents = false;
-    d.isQuantized = false;
-    d.sampleType = OutputDescriptor::FixedSampleRate;
-    d.sampleRate = 1;
-    d.hasDuration = false;
-    list.push_back(d);
-
-    return list;
-}
-
-bool
-TuningDifference::initialise(size_t channels, size_t stepSize, size_t blockSize)
-{
-    if (channels < getMinChannelCount() ||
-	channels > getMaxChannelCount()) return false;
-
-    if (blockSize != getPreferredBlockSize() ||
-	stepSize != blockSize/2) return false;
-
-    m_blockSize = blockSize;
-
-    reset();
-    
-    return true;
-}
-
-void
-TuningDifference::reset()
-{
-    m_sum[0].clear();
-    m_sum[1].clear();
-    m_frameCount = 0;
-}
-
-TuningDifference::FeatureSet
-TuningDifference::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
-{
-    for (int c = 0; c < 2; ++c) {
-	if (m_sum[c].size() == 0) {
-	    m_sum[c].resize(m_blockSize/2 + 1, 0.0);
-	}
-	vector<double> mags(m_blockSize/2 + 1, 0.0);
-	for (int i = 0; i <= m_blockSize/2; ++i) {
-	    double energy =
-		inputBuffers[c][i*2  ] * inputBuffers[c][i*2  ] +
-		inputBuffers[c][i*2+1] * inputBuffers[c][i*2+1];
-	    double mag = sqrt(energy);
-	    mags[i] = mag;
-	}
-	for (int i = 0; i <= m_blockSize/2; ++i) {
-	    for (int h = 2; h <= 4; ++h) {
-		double max = 0.0;
-		for (int j = 0; j <= h; ++j) {
-		    int ix = i * h + j - h/2;
-		    if (ix <= m_blockSize/2) {
-			double harmMag = mags[ix];
-			if (j == 0 || harmMag > max) {
-			    max = harmMag;
-			}
-		    }
-		}
-		mags[i] += max;
-	    }
-	}
-	for (int i = 0; i <= m_blockSize/2; ++i) {
-	    m_sum[c][i] += mags[i];
-	}
-    }
-    
-    ++m_frameCount;
-    return FeatureSet();
-}
-
-TuningDifference::FeatureSet
-TuningDifference::getRemainingFeatures()
-{
-    int n = m_sum[0].size();
-    if (n == 0) return FeatureSet();
-
-    Feature f;
-    FeatureSet fs;
-
-    int maxshift = 2400; // cents
-
-    int bestshift = -1;
-    double bestdist = 0;
-
-    for (int i = 0; i < n; ++i) {
-	m_sum[0][i] /= m_frameCount;
-	m_sum[1][i] /= m_frameCount;
-    }
-
-    for (int c = 0; c < 2; ++c) {
-	for (int i = 0; i < n; ++i) {
-	    if (i == 0 || i == n-1 ||
-		m_sum[c][i] < m_sum[c][i-1] ||
-		m_sum[c][i] < m_sum[c][i+1]) {
-		m_sum[c][i] = 0.0;
-	    }
-	}
-    }
-
-    int targetBinMin = int(floor(targetFmin * m_blockSize / m_inputSampleRate));
-    int targetBinMax = int(ceil(targetFmax * m_blockSize / m_inputSampleRate));
-    cerr << "target bin range: " << targetBinMin << " -> " << targetBinMax << endl;
-
-    for (int c = 0; c < 2; ++c) {
-	double tot = 0.0;
-	for (int i = targetBinMin; i <= targetBinMax; ++i) {
-	    tot += m_sum[c][i];
-	}
-	if (tot != 0.0) {
-	    for (int i = 0; i < n; ++i) {
-		m_sum[c][i] /= tot;
-	    }
-	}
-    }
-	
-    f.values.clear();
-    for (int i = targetBinMin; i < targetBinMax; ++i) {
-	f.values.push_back(m_sum[0][i]);
-    }
-    fs[3].push_back(f);
-    f.values.clear();
-    for (int i = targetBinMin; i < targetBinMax; ++i) {
-	f.values.push_back(m_sum[1][i]);
-    }
-    fs[3].push_back(f);
-
-    f.values.clear();
-    
-    for (int shift = -maxshift; shift <= maxshift; ++shift) {
-
-	double multiplier = pow(2.0, double(shift) / 1200.0);
-	double dist = 0.0;
-
-//	cerr << "shift = " << shift << ", multiplier = " << multiplier << endl;
-
-	int contributing = 0;
-	
-	for (int i = targetBinMin; i < targetBinMax; ++i) {
-
-	    double source = i / multiplier;
-	    int s0 = int(source), s1 = s0 + 1;
-	    double p1 = source - s0;
-	    double p0 = 1.0 - p1;
-
-	    double value = 0.0;
-	    if (s0 >= 0 && s0 < n) {
-		value += p0 * m_sum[1][s0];
-		++contributing;
-	    }
-	    if (s1 >= 0 && s1 < n) {
-		value += p1 * m_sum[1][s1];
-		++contributing;
-	    }
-
-//	    if (shift == -1) {
-//		cerr << "for multiplier " << multiplier << ", target " << i << ", source " << source << ", value " << p0 << " * " << m_sum[1][s0] << " + " << p1 << " * " << m_sum[1][s1] << " = " << value << ", other " << m_sum[0][i] << endl;
-//	    }
-	    
-	    double diff = fabs(m_sum[0][i] - value);
-	    dist += diff;
-	}
-
-	dist /= contributing;
-	
-	f.values.clear();
-	f.values.push_back(dist);
-	char label[100];
-	sprintf(label, "%f at shift %d freq mult %f", dist, shift, multiplier);
-	f.label = label;
-	fs[2].push_back(f);
-
-	if (bestshift == -1 || dist < bestdist) {
-	    bestshift = shift;
-	    bestdist = dist;
-	}
-    }
-
-    f.timestamp = Vamp::RealTime::zeroTime;
-    f.hasTimestamp = true;
-    f.label = "";
-
-    f.values.clear();
-    cerr << "best dist = " << bestdist << " at shift " << bestshift << endl;
-    f.values.push_back(-bestshift);
-    fs[0].push_back(f);
-
-    f.values.clear();
-    f.values.push_back(440.0 / pow(2.0, double(bestshift) / 1200.0));
-    fs[1].push_back(f);
-    
-    return fs;
-}
-
--- a/spectrum-compare-plugin/TuningDifference.h	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-#ifndef TUNING_DIFFERENCE_H
-#define TUNING_DIFFERENCE_H
-
-#include <vamp-sdk/Plugin.h>
-
-using std::string;
-using std::vector;
-
-class TuningDifference : public Vamp::Plugin
-{
-public:
-    TuningDifference(float inputSampleRate);
-    virtual ~TuningDifference();
-
-    string getIdentifier() const;
-    string getName() const;
-    string getDescription() const;
-    string getMaker() const;
-    int getPluginVersion() const;
-    string getCopyright() const;
-
-    InputDomain getInputDomain() const;
-    size_t getPreferredBlockSize() const;
-    size_t getPreferredStepSize() const;
-    size_t getMinChannelCount() const;
-    size_t getMaxChannelCount() const;
-
-    ParameterList getParameterDescriptors() const;
-    float getParameter(string identifier) const;
-    void setParameter(string identifier, float value);
-
-    ProgramList getPrograms() const;
-    string getCurrentProgram() const;
-    void selectProgram(string name);
-
-    OutputList getOutputDescriptors() const;
-
-    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
-    void reset();
-
-    FeatureSet process(const float *const *inputBuffers,
-                       Vamp::RealTime timestamp);
-
-    FeatureSet getRemainingFeatures();
-
-protected:
-    int m_blockSize;
-    vector<double> m_sum[2];
-    int m_frameCount;
-};
-
-
-#endif
--- a/spectrum-compare-plugin/plugins.cpp	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-
-#include <vamp/vamp.h>
-#include <vamp-sdk/PluginAdapter.h>
-
-#include "TuningDifference.h"
-
-static Vamp::PluginAdapter<TuningDifference> tdAdapter;
-
-
-const VampPluginDescriptor *
-vampGetPluginDescriptor(unsigned int version, unsigned int index)
-{
-    if (version < 1) return 0;
-
-    switch (index) {
-    case  0: return tdAdapter.getDescriptor();
-    default: return 0;
-    }
-}
-
-
--- a/spectrum-compare-plugin/vamp-plugin.list	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-_vampGetPluginDescriptor
--- a/spectrum-compare-plugin/vamp-plugin.map	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-{
-	global: vampGetPluginDescriptor;
-	local: *;
-};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/TuningDifference.cpp	Thu Feb 05 10:13:31 2015 +0000
@@ -0,0 +1,492 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+  Centre for Digital Music, Queen Mary University of London.
+    
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.  See the file
+  COPYING included with this distribution for more information.
+*/
+
+#include "TuningDifference.h"
+
+#include <iostream>
+
+#include <cmath>
+#include <cstdio>
+
+#include <algorithm>
+
+using namespace std;
+
+static double pitchToFrequency(int pitch,
+			       double centsOffset = 0.,
+			       double concertA = 440.)
+{
+    double p = double(pitch) + (centsOffset / 100.);
+    return concertA * pow(2.0, (p - 69.0) / 12.0); 
+}
+
+static double frequencyForCentsAbove440(double cents)
+{
+    return pitchToFrequency(69, cents, 440.);
+}
+
+TuningDifference::TuningDifference(float inputSampleRate) :
+    Plugin(inputSampleRate),
+    m_bpo(60),
+    m_refChroma(new Chromagram(paramsForTuningFrequency(440.))),
+    m_blockSize(0),
+    m_frameCount(0)
+{
+}
+
+TuningDifference::~TuningDifference()
+{
+}
+
+string
+TuningDifference::getIdentifier() const
+{
+    return "tuning-difference";
+}
+
+string
+TuningDifference::getName() const
+{
+    return "Tuning Difference";
+}
+
+string
+TuningDifference::getDescription() const
+{
+    // Return something helpful here!
+    return "";
+}
+
+string
+TuningDifference::getMaker() const
+{
+    // Your name here
+    return "";
+}
+
+int
+TuningDifference::getPluginVersion() const
+{
+    // Increment this each time you release a version that behaves
+    // differently from the previous one
+    return 1;
+}
+
+string
+TuningDifference::getCopyright() const
+{
+    // This function is not ideally named.  It does not necessarily
+    // need to say who made the plugin -- getMaker does that -- but it
+    // should indicate the terms under which it is distributed.  For
+    // example, "Copyright (year). All Rights Reserved", or "GPL"
+    return "";
+}
+
+TuningDifference::InputDomain
+TuningDifference::getInputDomain() const
+{
+    return TimeDomain;
+}
+
+size_t
+TuningDifference::getPreferredBlockSize() const
+{
+    return 0;
+}
+
+size_t 
+TuningDifference::getPreferredStepSize() const
+{
+    return 0;
+}
+
+size_t
+TuningDifference::getMinChannelCount() const
+{
+    return 2;
+}
+
+size_t
+TuningDifference::getMaxChannelCount() const
+{
+    return 2;
+}
+
+TuningDifference::ParameterList
+TuningDifference::getParameterDescriptors() const
+{
+    ParameterList list;
+    //!!! parameter: max search range
+    //!!! parameter: fine search precision
+    return list;
+}
+
+float
+TuningDifference::getParameter(string) const
+{
+    return 0;
+}
+
+void
+TuningDifference::setParameter(string, float) 
+{
+}
+
+TuningDifference::ProgramList
+TuningDifference::getPrograms() const
+{
+    ProgramList list;
+    return list;
+}
+
+string
+TuningDifference::getCurrentProgram() const
+{
+    return ""; // no programs
+}
+
+void
+TuningDifference::selectProgram(string)
+{
+}
+
+TuningDifference::OutputList
+TuningDifference::getOutputDescriptors() const
+{
+    OutputList list;
+
+    OutputDescriptor d;
+    d.identifier = "cents";
+    d.name = "Tuning Difference";
+    d.description = "Difference in averaged frequency profile between channels 1 and 2, in cents. A positive value means channel 2 is higher.";
+    d.unit = "cents";
+    d.hasFixedBinCount = true;
+    d.binCount = 1;
+    d.hasKnownExtents = false;
+    d.isQuantized = false;
+    d.sampleType = OutputDescriptor::VariableSampleRate;
+    d.hasDuration = false;
+    m_outputs[d.identifier] = list.size();
+    list.push_back(d);
+
+    d.identifier = "tuningfreq";
+    d.name = "Relative Tuning Frequency";
+    d.description = "Tuning frequency of channel 2, if channel 1 is assumed to contain the same music as it at a tuning frequency of A=440Hz.";
+    d.unit = "hz";
+    d.hasFixedBinCount = true;
+    d.binCount = 1;
+    d.hasKnownExtents = false;
+    d.isQuantized = false;
+    d.sampleType = OutputDescriptor::VariableSampleRate;
+    d.hasDuration = false;
+    m_outputs[d.identifier] = list.size();
+    list.push_back(d);
+
+    d.identifier = "reffeature";
+    d.name = "Reference Feature";
+    d.description = "Chroma feature from reference audio.";
+    d.unit = "";
+    d.hasFixedBinCount = true;
+    d.binCount = m_bpo;
+    d.hasKnownExtents = false;
+    d.isQuantized = false;
+    d.sampleType = OutputDescriptor::FixedSampleRate;
+    d.sampleRate = 1;
+    d.hasDuration = false;
+    m_outputs[d.identifier] = list.size();
+    list.push_back(d);
+
+    d.identifier = "otherfeature";
+    d.name = "Other Feature";
+    d.description = "Chroma feature from other audio, before rotation.";
+    d.unit = "";
+    d.hasFixedBinCount = true;
+    d.binCount = m_bpo;
+    d.hasKnownExtents = false;
+    d.isQuantized = false;
+    d.sampleType = OutputDescriptor::FixedSampleRate;
+    d.sampleRate = 1;
+    d.hasDuration = false;
+    m_outputs[d.identifier] = list.size();
+    list.push_back(d);
+
+    d.identifier = "rotfeature";
+    d.name = "Other Feature at Rotated Frequency";
+    d.description = "Chroma feature from reference audio calculated with the tuning frequency obtained from rotation matching.";
+    d.unit = "";
+    d.hasFixedBinCount = true;
+    d.binCount = m_bpo;
+    d.hasKnownExtents = false;
+    d.isQuantized = false;
+    d.sampleType = OutputDescriptor::FixedSampleRate;
+    d.sampleRate = 1;
+    d.hasDuration = false;
+    m_outputs[d.identifier] = list.size();
+    list.push_back(d);
+
+    return list;
+}
+
+bool
+TuningDifference::initialise(size_t channels, size_t stepSize, size_t blockSize)
+{
+    if (channels < getMinChannelCount() ||
+	channels > getMaxChannelCount()) return false;
+
+    if (stepSize != blockSize) return false;
+
+    m_blockSize = blockSize;
+
+    reset();
+    
+    return true;
+}
+
+void
+TuningDifference::reset()
+{
+    if (m_frameCount > 0) {
+	m_refChroma.reset(new Chromagram(paramsForTuningFrequency(440.)));
+	m_frameCount = 0;
+    }
+    m_refTotals = TFeature(m_bpo, 0.0);
+    m_other.clear();
+}
+
+template<typename T>
+void addTo(vector<T> &a, const vector<T> &b)
+{
+    transform(a.begin(), a.end(), b.begin(), a.begin(), plus<T>());
+}
+
+template<typename T>
+T distance(const vector<T> &a, const vector<T> &b)
+{
+    return inner_product(a.begin(), a.end(), b.begin(), T(),
+			 plus<T>(), [](T x, T y) { return fabs(x - y); });
+}
+
+TuningDifference::TFeature
+TuningDifference::computeFeatureFromTotals(const TFeature &totals) const
+{
+    if (m_frameCount == 0) return totals;
+    
+    TFeature feature(m_bpo);
+    double sum = 0.0;
+
+    for (int i = 0; i < m_bpo; ++i) {
+	double value = totals[i] / m_frameCount;
+	feature[i] += value;
+	sum += value;
+    }
+
+    for (int i = 0; i < m_bpo; ++i) {
+	feature[i] /= sum;
+    }
+
+    cerr << "computeFeatureFromTotals: feature values:" << endl;
+    for (auto v: feature) cerr << v << " ";
+    cerr << endl;
+    
+    return feature;
+}
+
+Chromagram::Parameters
+TuningDifference::paramsForTuningFrequency(double hz) const
+{
+    Chromagram::Parameters params(m_inputSampleRate);
+    params.lowestOctave = 0;
+    params.octaveCount = 6;
+    params.binsPerOctave = m_bpo;
+    params.tuningFrequency = hz;
+    params.atomHopFactor = 0.5;
+    return params;
+}
+
+TuningDifference::TFeature
+TuningDifference::computeFeatureFromSignal(const Signal &signal, double hz) const
+{
+    Chromagram chromagram(paramsForTuningFrequency(hz));
+
+    TFeature totals(m_bpo, 0.0);
+
+    cerr << "computeFeatureFromSignal: hz = " << hz << ", frame count = " << m_frameCount << endl;
+    
+    for (int i = 0; i < m_frameCount; ++i) {
+	Signal::const_iterator first = signal.begin() + i * m_blockSize;
+	Signal::const_iterator last = first + m_blockSize;
+	if (last > signal.end()) last = signal.end();
+	CQBase::RealSequence input(first, last);
+	input.resize(m_blockSize);
+	CQBase::RealBlock block = chromagram.process(input);
+	for (const auto &v: block) addTo(totals, v);
+    }
+
+    return computeFeatureFromTotals(totals);
+}
+
+TuningDifference::FeatureSet
+TuningDifference::process(const float *const *inputBuffers, Vamp::RealTime)
+{
+    CQBase::RealBlock block;
+    CQBase::RealSequence input;
+
+    input = CQBase::RealSequence
+	(inputBuffers[0], inputBuffers[0] + m_blockSize);
+    block = m_refChroma->process(input);
+    for (const auto &v: block) addTo(m_refTotals, v);
+
+    m_other.insert(m_other.end(),
+		   inputBuffers[1], inputBuffers[1] + m_blockSize);
+    
+    ++m_frameCount;
+    return FeatureSet();
+}
+
+double
+TuningDifference::featureDistance(const TFeature &other, int rotation) const
+{
+    if (rotation == 0) {
+	return distance(m_refFeature, other);
+    } else {
+	// A positive rotation pushes the tuning frequency up for this
+	// chroma, negative one pulls it down. If a positive rotation
+	// makes this chroma match an un-rotated reference, then this
+	// chroma must have initially been lower than the reference.
+	TFeature r(other);
+	if (rotation < 0) {
+	    rotate(r.begin(), r.begin() - rotation, r.end());
+	} else {
+	    rotate(r.begin(), r.end() - rotation, r.end());
+	}
+	return distance(m_refFeature, r);
+    }
+}
+
+int
+TuningDifference::findBestRotation(const TFeature &other) const
+{
+    map<double, int> dists;
+
+    int maxSemis = 6;
+    int maxRotation = (m_bpo * maxSemis) / 12;
+
+    for (int r = -maxRotation; r <= maxRotation; ++r) {
+	double dist = featureDistance(other, r);
+	dists[dist] = r;
+	cerr << "rotation " << r << ": score " << dist << endl;
+    }
+
+    int best = dists.begin()->second;
+
+    cerr << "best is " << best << endl;
+    return best;
+}
+
+pair<int, double>
+TuningDifference::findFineFrequency(int coarseCents, double coarseScore)
+{
+    int coarseResolution = 1200 / m_bpo;
+    int searchDistance = coarseResolution/2 - 1;
+
+    double bestScore = coarseScore;
+    int bestCents = coarseCents;
+    double bestHz = frequencyForCentsAbove440(coarseCents);
+
+    cerr << "corresponding coarse Hz " << bestHz << " scores " << coarseScore << endl;
+    cerr << "searchDistance = " << searchDistance << endl;
+    
+    for (int sign = -1; sign <= 1; sign += 2) {
+	for (int offset = 1; offset <= searchDistance; ++offset) {
+
+	    int fineCents = coarseCents + sign * offset;
+
+	    cerr << "trying with fineCents = " << fineCents << "..." << endl;
+	    
+	    double fineHz = frequencyForCentsAbove440(fineCents);
+	    TFeature fineFeature = computeFeatureFromSignal(m_other, fineHz);
+	    double fineScore = featureDistance(fineFeature);
+
+	    cerr << "fine offset = " << offset << ", cents = " << fineCents
+		 << ", Hz = " << fineHz << ", score " << fineScore
+		 << " (best score so far " << bestScore << ")" << endl;
+	    
+	    if (fineScore < bestScore) {
+		cerr << "is good!" << endl;
+		bestScore = fineScore;
+		bestCents = fineCents;
+		bestHz = fineHz;
+	    } else {
+		break;
+	    }
+	}
+    }
+
+    //!!! could keep a vector of scores & then interpolate...
+    
+    return pair<int, double>(bestCents, bestHz);
+}
+
+TuningDifference::FeatureSet
+TuningDifference::getRemainingFeatures()
+{
+    FeatureSet fs;
+    if (m_frameCount == 0) return fs;
+
+    m_refFeature = computeFeatureFromTotals(m_refTotals);
+    TFeature otherFeature = computeFeatureFromSignal(m_other, 440.);
+
+    Feature f;
+
+    f.values.clear();
+    for (auto v: m_refFeature) f.values.push_back(v);
+    fs[m_outputs["reffeature"]].push_back(f);
+
+    f.values.clear();
+    for (auto v: otherFeature) f.values.push_back(v);
+    fs[m_outputs["otherfeature"]].push_back(f); 
+   
+    int rotation = findBestRotation(otherFeature);
+
+    int coarseCents = -(rotation * 1200) / m_bpo;
+
+    cerr << "rotation " << rotation << " -> cents " << coarseCents << endl;
+
+    double coarseHz = frequencyForCentsAbove440(coarseCents);
+
+    TFeature coarseFeature = computeFeatureFromSignal(m_other, coarseHz);
+    double coarseScore = featureDistance(coarseFeature);
+
+    cerr << "corresponding Hz " << coarseHz << " scores " << coarseScore << endl;
+
+    //!!! This should be returning the fine chroma, not the coarse
+    f.values.clear();
+    for (auto v: coarseFeature) f.values.push_back(v);
+    fs[m_outputs["rotfeature"]].push_back(f);
+
+    pair<int, double> fine = findFineFrequency(coarseCents, coarseScore);
+    int fineCents = fine.first;
+    double fineHz = fine.second;
+
+    f.values.clear();
+    f.values.push_back(fineHz);
+    fs[m_outputs["tuningfreq"]].push_back(f);
+
+    f.values.clear();
+    f.values.push_back(fineCents);
+    fs[m_outputs["cents"]].push_back(f);
+    
+    cerr << "overall best Hz = " << fineHz << endl;
+    
+    return fs;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/TuningDifference.h	Thu Feb 05 10:13:31 2015 +0000
@@ -0,0 +1,85 @@
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+  Centre for Digital Music, Queen Mary University of London.
+    
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.  See the file
+  COPYING included with this distribution for more information.
+*/
+
+#ifndef TUNING_DIFFERENCE_H
+#define TUNING_DIFFERENCE_H
+
+#include <vamp-sdk/Plugin.h>
+
+#include <cq/Chromagram.h>
+
+#include <memory>
+
+using std::string;
+using std::vector;
+
+class TuningDifference : public Vamp::Plugin
+{
+public:
+    TuningDifference(float inputSampleRate);
+    virtual ~TuningDifference();
+
+    string getIdentifier() const;
+    string getName() const;
+    string getDescription() const;
+    string getMaker() const;
+    int getPluginVersion() const;
+    string getCopyright() const;
+
+    InputDomain getInputDomain() const;
+    size_t getPreferredBlockSize() const;
+    size_t getPreferredStepSize() const;
+    size_t getMinChannelCount() const;
+    size_t getMaxChannelCount() const;
+
+    ParameterList getParameterDescriptors() const;
+    float getParameter(string identifier) const;
+    void setParameter(string identifier, float value);
+
+    ProgramList getPrograms() const;
+    string getCurrentProgram() const;
+    void selectProgram(string name);
+
+    OutputList getOutputDescriptors() const;
+
+    bool initialise(size_t channels, size_t stepSize, size_t blockSize);
+    void reset();
+
+    FeatureSet process(const float *const *inputBuffers,
+                       Vamp::RealTime timestamp);
+
+    FeatureSet getRemainingFeatures();
+
+protected:
+    typedef vector<float> Signal;
+    typedef vector<double> TFeature;
+
+    int m_bpo;
+    std::unique_ptr<Chromagram> m_refChroma;
+    TFeature m_refTotals;
+    TFeature m_refFeature;
+    Signal m_other;
+    int m_blockSize;
+    int m_frameCount;
+
+    Chromagram::Parameters paramsForTuningFrequency(double hz) const;
+    TFeature computeFeatureFromTotals(const TFeature &totals) const;
+    TFeature computeFeatureFromSignal(const Signal &signal, double hz) const;
+    double featureDistance(const TFeature &other, int rotation = 0) const;
+    int findBestRotation(const TFeature &other) const;
+    std::pair<int, double> findFineFrequency(int coarseCents, double coarseScore);
+
+    mutable std::map<string, int> m_outputs;
+};
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins.cpp	Thu Feb 05 10:13:31 2015 +0000
@@ -0,0 +1,21 @@
+
+#include <vamp/vamp.h>
+#include <vamp-sdk/PluginAdapter.h>
+
+#include "TuningDifference.h"
+
+static Vamp::PluginAdapter<TuningDifference> tdAdapter;
+
+
+const VampPluginDescriptor *
+vampGetPluginDescriptor(unsigned int version, unsigned int index)
+{
+    if (version < 1) return 0;
+
+    switch (index) {
+    case  0: return tdAdapter.getDescriptor();
+    default: return 0;
+    }
+}
+
+
--- a/tuning-and-key/keycompare.sh	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-#!/bin/bash
-
-##!!! This is unfinished -- abandoned because a premise turned out not to be sound
-
-set -e
-
-mypath=`dirname $0`
-
-sonic-annotator --minversion 1.1 || exit 1
-
-reference="$1"
-other="$2"
-
-usage() {
-    echo "Usage: $0 reference.wav other.wav" 1>&2
-    exit 2
-}
-
-test -n "$reference" || usage
-test -n "$other" || usage
-
-set -u
-
-transform="/tmp/$$.ttl"
-trap "rm $transform" 0
-
-provisional=$(sonic-annotator -d vamp:nnls-chroma:tuning:tuning "$other" -w csv --csv-stdout | tail -1 | awk -F, '{ print $4 }')
-
-ref_tonic=$(sonic-annotator -t "keydetector.ttl" "$reference" -w csv --csv-stdout --csv-omit-filename --summary mode|tail -1|awk -F, '{ print $4 }')
-
-cat "keydetector.ttl" | sed "s,440,$provisional," > "$transform"
-
-tonic=$(sonic-annotator -t "$transform" "$other" -w csv --csv-stdout --csv-omit-filename --summary mode|tail -1|awk -F, '{ print $4 }')
-
-# modular arithmetic here is wrong. but it turns out our tuning freq
-# estimation above is also wrong anyway for our test file
-
-sum="print ($provisional * (2.0 ** ((($tonic - $ref_tonic) % 12) / 12.0)))"
-freq=$(perl -e "$sum")
-
-echo "Sum is: $sum"
-echo "Estimated frequency is $freq (provisional: $provisional; reference tonic: $ref_tonic; test tonic: $tonic)"
-
--- a/tuning-and-key/keydetector.ttl	Thu Feb 05 09:52:28 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-@prefix xsd:      <http://www.w3.org/2001/XMLSchema#> .
-@prefix vamp:     <http://purl.org/ontology/vamp/> .
-@prefix :         <#> .
-
-:param_tuningfreq
-    vamp:parameter [ vamp:identifier "tuning" ] ;
-    vamp:value "440"^^xsd:float .
-
-:transform_a a vamp:Transform ;
-    vamp:plugin <http://vamp-plugins.org/rdf/plugins/qm-vamp-plugins#qm-keydetector> ;
-    vamp:sample_rate "44100"^^xsd:int ;
-    vamp:parameter_binding :param_tuningfreq ;
-    vamp:output [ vamp:identifier "tonic" ] .
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-plugin.list	Thu Feb 05 10:13:31 2015 +0000
@@ -0,0 +1,1 @@
+_vampGetPluginDescriptor
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vamp-plugin.map	Thu Feb 05 10:13:31 2015 +0000
@@ -0,0 +1,4 @@
+{
+	global: vampGetPluginDescriptor;
+	local: *;
+};