add queen mary DSP library

git-svn-id: svn://localhost/ardour2/branches/3.0@9029 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2011-03-02 12:37:39 +00:00
parent fa41cfef58
commit 3deba1921b
85 changed files with 69852 additions and 0 deletions

280
libs/qm-dsp/COPYING Normal file
View File

@ -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

33
libs/qm-dsp/README.txt Normal file
View File

@ -0,0 +1,33 @@
QM-DSP library
==============
This is a C++ library of functions for DSP and Music Informatics
purposes developed at Queen Mary, University of London.
It is used by the QM Vamp Plugins (q.v.) amongst other things.
This code is Copyright (c) 2006-2010 Queen Mary, University of London,
with the following exceptions:
maths/pca.c -- Fionn Murtagh, from StatLib; with permission
maths/Polyfit.h -- Allen Miller, David J Taylor and others; also for
Delphi in the the JEDI Math Library, under the Mozilla Public License
thread/BlockAllocator.h -- derived from FSB Allocator by Juha Nieminen,
under BSD-style license
See individual files for further authorship details.
License
=======
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.

View File

@ -0,0 +1,46 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP library
Centre for Digital Music, Queen Mary, University of London.
This file Copyright 2006 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
*/
#include "Pitch.h"
#include <math.h>
float
Pitch::getFrequencyForPitch(int midiPitch,
float centsOffset,
float concertA)
{
float p = float(midiPitch) + (centsOffset / 100);
return concertA * powf(2.0, (p - 69.0) / 12.0);
}
int
Pitch::getPitchForFrequency(float frequency,
float *centsOffsetReturn,
float concertA)
{
float p = 12.0 * (log(frequency / (concertA / 2.0)) / log(2.0)) + 57.0;
int midiPitch = int(p + 0.00001);
float centsOffset = (p - midiPitch) * 100.0;
if (centsOffset >= 50.0) {
midiPitch = midiPitch + 1;
centsOffset = -(100.0 - centsOffset);
}
if (centsOffsetReturn) *centsOffsetReturn = centsOffset;
return midiPitch;
}

31
libs/qm-dsp/base/Pitch.h Normal file
View File

@ -0,0 +1,31 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP library
Centre for Digital Music, Queen Mary, University of London.
This file Copyright 2006 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
*/
#ifndef _PITCH_H_
#define _PITCH_H_
class Pitch
{
public:
static float getFrequencyForPitch(int midiPitch,
float centsOffset = 0,
float concertA = 440.0);
static int getPitchForFrequency(float frequency,
float *centsOffsetReturn = 0,
float concertA = 440.0);
};
#endif

125
libs/qm-dsp/base/Window.h Normal file
View File

@ -0,0 +1,125 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP library
Centre for Digital Music, Queen Mary, University of London.
This file Copyright 2006 Chris Cannam.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
*/
#ifndef _WINDOW_H_
#define _WINDOW_H_
#include <cmath>
#include <iostream>
#include <map>
enum WindowType {
RectangularWindow,
BartlettWindow,
HammingWindow,
HanningWindow,
BlackmanWindow,
GaussianWindow,
ParzenWindow
};
template <typename T>
class Window
{
public:
/**
* Construct a windower of the given type.
*/
Window(WindowType type, size_t size) : m_type(type), m_size(size) { encache(); }
Window(const Window &w) : m_type(w.m_type), m_size(w.m_size) { encache(); }
Window &operator=(const Window &w) {
if (&w == this) return *this;
m_type = w.m_type;
m_size = w.m_size;
encache();
return *this;
}
virtual ~Window() { delete[] m_cache; }
void cut(T *src) const { cut(src, src); }
void cut(const T *src, T *dst) const {
for (size_t i = 0; i < m_size; ++i) dst[i] = src[i] * m_cache[i];
}
WindowType getType() const { return m_type; }
size_t getSize() const { return m_size; }
protected:
WindowType m_type;
size_t m_size;
T *m_cache;
void encache();
};
template <typename T>
void Window<T>::encache()
{
size_t n = m_size;
T *mult = new T[n];
size_t i;
for (i = 0; i < n; ++i) mult[i] = 1.0;
switch (m_type) {
case RectangularWindow:
for (i = 0; i < n; ++i) {
mult[i] = mult[i] * 0.5;
}
break;
case BartlettWindow:
for (i = 0; i < n/2; ++i) {
mult[i] = mult[i] * (i / T(n/2));
mult[i + n/2] = mult[i + n/2] * (1.0 - (i / T(n/2)));
}
break;
case HammingWindow:
for (i = 0; i < n; ++i) {
mult[i] = mult[i] * (0.54 - 0.46 * cos(2 * M_PI * i / n));
}
break;
case HanningWindow:
for (i = 0; i < n; ++i) {
mult[i] = mult[i] * (0.50 - 0.50 * cos(2 * M_PI * i / n));
}
break;
case BlackmanWindow:
for (i = 0; i < n; ++i) {
mult[i] = mult[i] * (0.42 - 0.50 * cos(2 * M_PI * i / n)
+ 0.08 * cos(4 * M_PI * i / n));
}
break;
case GaussianWindow:
for (i = 0; i < n; ++i) {
mult[i] = mult[i] * exp((-1.0 / (n*n)) * ((T(2*i) - n) *
(T(2*i) - n)));
}
break;
case ParzenWindow:
for (i = 0; i < n; ++i) {
mult[i] = mult[i] * (1.0 - fabs((T(2*i) - n) / T(n + 1)));
}
break;
}
m_cache = mult;
}
#endif

View File

@ -0,0 +1,101 @@
#
# qmake configuration for win32-g++
#
# Written for MinGW
#
MAKEFILE_GENERATOR = MINGW
TEMPLATE = app
CONFIG += qt warn_on release link_prl copy_dir_files debug_and_release debug_and_release_target
QT += core gui
DEFINES += UNICODE QT_LARGEFILE_SUPPORT
QMAKE_COMPILER_DEFINES += __GNUC__ WIN32
QMAKE_CC = i586-mingw32msvc-gcc
QMAKE_LEX = flex
QMAKE_LEXFLAGS =
QMAKE_YACC = byacc
QMAKE_YACCFLAGS = -d
QMAKE_CFLAGS =
QMAKE_CFLAGS_DEPS = -M
QMAKE_CFLAGS_WARN_ON = -Wall
QMAKE_CFLAGS_WARN_OFF = -w
QMAKE_CFLAGS_RELEASE = -O2
QMAKE_CFLAGS_DEBUG = -g
QMAKE_CFLAGS_YACC = -Wno-unused -Wno-parentheses
QMAKE_CFLAGS_THREAD = -mthreads
QMAKE_CXX = i586-mingw32msvc-g++
QMAKE_CXXFLAGS = $$QMAKE_CFLAGS
QMAKE_CXXFLAGS_DEPS = $$QMAKE_CFLAGS_DEPS
QMAKE_CXXFLAGS_WARN_ON = $$QMAKE_CFLAGS_WARN_ON
QMAKE_CXXFLAGS_WARN_OFF = $$QMAKE_CFLAGS_WARN_OFF
QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE
QMAKE_CXXFLAGS_DEBUG = $$QMAKE_CFLAGS_DEBUG
QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC
QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD
QMAKE_CXXFLAGS_RTTI_ON = -frtti
QMAKE_CXXFLAGS_RTTI_OFF = -fno-rtti
QMAKE_CXXFLAGS_EXCEPTIONS_ON = -fexceptions
QMAKE_CXXFLAGS_EXCEPTIONS_OFF = -fno-exceptions
QMAKE_INCDIR =
QMAKE_INCDIR_QT = /home/studio/.wine/fake_windows/Qt/4.3.0/include
QMAKE_LIBDIR_QT = /home/studio/.wine/fake_windows/Qt/4.3.0/lib
QMAKE_RUN_CC = $(CC) -c $(CFLAGS) $(INCPATH) -o $obj $src
QMAKE_RUN_CC_IMP = $(CC) -c $(CFLAGS) $(INCPATH) -o $@ $<
QMAKE_RUN_CXX = $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $obj $src
QMAKE_RUN_CXX_IMP = $(CXX) -c $(CXXFLAGS) $(INCPATH) -o $@ $<
QMAKE_LINK = i586-mingw32msvc-g++
QMAKE_LFLAGS = -Wl,-enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc -mwindows
QMAKE_LFLAGS_RELEASE = -Wl,-s
QMAKE_LFLAGS_DEBUG =
QMAKE_LFLAGS_CONSOLE = -Wl,-subsystem,console
QMAKE_LFLAGS_WINDOWS = -Wl,-subsystem,windows
QMAKE_LFLAGS_DLL = -shared
QMAKE_LINK_OBJECT_MAX = 10
QMAKE_LINK_OBJECT_SCRIPT= object_script
QMAKE_LIBS =
QMAKE_LIBS_CORE = -lkernel32 -luser32 -lshell32 -luuid -lole32 -ladvapi32 -lws2_32
#QMAKE_LIBS_CORE = -lkernel32 -luser32 -luuid -lole32 -ladvapi32 -lws2_32
QMAKE_LIBS_GUI = -lgdi32 -lcomdlg32 -loleaut32 -limm32 -lwinmm -lwinspool -lws2_32 -lole32 -luuid -luser32
QMAKE_LIBS_NETWORK = -lws2_32
QMAKE_LIBS_OPENGL = -lopengl32 -lglu32 -lgdi32 -luser32
QMAKE_LIBS_COMPAT = -ladvapi32 -lshell32 -lcomdlg32 -luser32 -lgdi32 -lws2_32
QMAKE_LIBS_QT_ENTRY = -lqtmain
MINGW_IN_SHELL = $$(MINGW_IN_SHELL)
#isEqual(MINGW_IN_SHELL, 1) {
QMAKE_DIR_SEP = /
QMAKE_COPY = cp
QMAKE_COPY_DIR = cp -r
QMAKE_MOVE = mv
QMAKE_DEL_FILE = rm -f
QMAKE_MKDIR = mkdir -p
QMAKE_DEL_DIR = rm -rf
#} else {
# QMAKE_COPY = copy /y
# QMAKE_COPY_DIR = xcopy /s /q /y /i
# QMAKE_MOVE = move
# QMAKE_DEL_FILE = del
# QMAKE_MKDIR = mkdir
# QMAKE_DEL_DIR = rmdir
#}
QMAKE_MOC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}moc
QMAKE_UIC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}uic
QMAKE_IDC = $$[QT_INSTALL_BINS]$${DIR_SEPARATOR}idc
QMAKE_IDL = midl
QMAKE_LIB = ar -ru
QMAKE_RC = i586-mingw32msvc-windres
QMAKE_ZIP = zip -r -9
QMAKE_STRIP = strip
QMAKE_STRIPFLAGS_LIB += --strip-unneeded
QMAKE_CHK_DIR_EXISTS = test -d
load(qt_config)

View File

@ -0,0 +1,146 @@
/****************************************************************************
**
** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.
**
** This file is part of the qmake spec of the Qt Toolkit.
**
** This file may be used under the terms of the GNU General Public
** License version 2.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
** http://www.trolltech.com/products/qt/opensource.html
**
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://www.trolltech.com/products/qt/licensing.html or contact the
** sales department at sales@trolltech.com.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef QPLATFORMDEFS_H
#define QPLATFORMDEFS_H
#ifdef UNICODE
#ifndef _UNICODE
#define _UNICODE
#endif
#endif
// Get Qt defines/settings
#include "qglobal.h"
#include <tchar.h>
#include <io.h>
#include <direct.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <windows.h>
#include <limits.h>
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT-0 < 0x0500)
typedef enum {
NameUnknown = 0,
NameFullyQualifiedDN = 1,
NameSamCompatible = 2,
NameDisplay = 3,
NameUniqueId = 6,
NameCanonical = 7,
NameUserPrincipal = 8,
NameCanonicalEx = 9,
NameServicePrincipal = 10,
NameDnsDomain = 12
} EXTENDED_NAME_FORMAT, *PEXTENDED_NAME_FORMAT;
#endif
#define Q_FS_FAT
#ifdef QT_LARGEFILE_SUPPORT
#define QT_STATBUF struct _stati64 // non-ANSI defs
#define QT_STATBUF4TSTAT struct _stati64 // non-ANSI defs
#define QT_STAT ::_stati64
#define QT_FSTAT ::_fstati64
#else
#define QT_STATBUF struct _stat // non-ANSI defs
#define QT_STATBUF4TSTAT struct _stat // non-ANSI defs
#define QT_STAT ::_stat
#define QT_FSTAT ::_fstat
#endif
#define QT_STAT_REG _S_IFREG
#define QT_STAT_DIR _S_IFDIR
#define QT_STAT_MASK _S_IFMT
#if defined(_S_IFLNK)
# define QT_STAT_LNK _S_IFLNK
#endif
#define QT_FILENO _fileno
#define QT_OPEN ::_open
#define QT_CLOSE ::_close
#ifdef QT_LARGEFILE_SUPPORT
#define QT_LSEEK ::_lseeki64
#ifndef UNICODE
#define QT_TSTAT ::_stati64
#else
#define QT_TSTAT ::_wstati64
#endif
#else
#define QT_LSEEK ::_lseek
#ifndef UNICODE
#define QT_TSTAT ::_stat
#else
#define QT_TSTAT ::_wstat
#endif
#endif
#define QT_READ ::_read
#define QT_WRITE ::_write
#define QT_ACCESS ::_access
#define QT_GETCWD ::_getcwd
#define QT_CHDIR ::_chdir
#define QT_MKDIR ::_mkdir
#define QT_RMDIR ::_rmdir
#define QT_OPEN_LARGEFILE 0
#define QT_OPEN_RDONLY _O_RDONLY
#define QT_OPEN_WRONLY _O_WRONLY
#define QT_OPEN_RDWR _O_RDWR
#define QT_OPEN_CREAT _O_CREAT
#define QT_OPEN_TRUNC _O_TRUNC
#define QT_OPEN_APPEND _O_APPEND
#if defined(O_TEXT)
# define QT_OPEN_TEXT _O_TEXT
# define QT_OPEN_BINARY _O_BINARY
#endif
#define QT_FOPEN ::fopen
#ifdef QT_LARGEFILE_SUPPORT
#define QT_FSEEK ::fseeko64
#define QT_FTELL ::ftello64
#else
#define QT_FSEEK ::fseek
#define QT_FTELL ::ftell
#endif
#define QT_FGETPOS ::fgetpos
#define QT_FSETPOS ::fsetpos
#define QT_FPOS_T fpos_t
#ifdef QT_LARGEFILE_SUPPORT
#define QT_OFF_T off64_t
#else
#define QT_OFF_T long
#endif
#define QT_SIGNAL_ARGS int
#define QT_VSNPRINTF ::_vsnprintf
#define QT_SNPRINTF ::_snprintf
# define F_OK 0
# define X_OK 1
# define W_OK 2
# define R_OK 4
#endif // QPLATFORMDEFS_H

View File

@ -0,0 +1,106 @@
TEMPLATE = lib
CONFIG += warn_on staticlib release
CONFIG -= qt
OBJECTS_DIR = tmp_obj
MOC_DIR = tmp_moc
linux-g++:QMAKE_CXXFLAGS_RELEASE += -DNDEBUG -O3 -march=pentium4 -msse -msse2
QMAKE_CXXFLAGS_RELEASE += -DNDEBUG -O2 -march=pentium3 -msse
#DEPENDPATH += base \
# dsp/chromagram \
# dsp/keydetection \
# dsp/maths \
# dsp/onsets \
# dsp/phasevocoder \
# dsp/rateconversion \
# dsp/signalconditioning \
# dsp/tempotracking \
# dsp/tonal \
# dsp/transforms
INCLUDEPATH += . include
# Input
HEADERS += base/Pitch.h \
base/Window.h \
dsp/chromagram/Chromagram.h \
dsp/chromagram/ChromaProcess.h \
dsp/chromagram/ConstantQ.h \
dsp/keydetection/GetKeyMode.h \
dsp/mfcc/MFCC.h \
dsp/onsets/DetectionFunction.h \
dsp/onsets/PeakPicking.h \
dsp/phasevocoder/PhaseVocoder.h \
dsp/rateconversion/Decimator.h \
dsp/rhythm/BeatSpectrum.h \
dsp/segmentation/cluster_melt.h \
dsp/segmentation/ClusterMeltSegmenter.h \
dsp/segmentation/cluster_segmenter.h \
dsp/segmentation/SavedFeatureSegmenter.h \
dsp/segmentation/Segmenter.h \
dsp/segmentation/segment.h \
dsp/signalconditioning/DFProcess.h \
dsp/signalconditioning/Filter.h \
dsp/signalconditioning/FiltFilt.h \
dsp/signalconditioning/Framer.h \
dsp/tempotracking/DownBeat.h \
dsp/tempotracking/TempoTrack.h \
dsp/tempotracking/TempoTrackV2.h \
dsp/tonal/ChangeDetectionFunction.h \
dsp/tonal/TCSgram.h \
dsp/tonal/TonalEstimator.h \
dsp/transforms/FFT.h \
dsp/transforms/kissfft/kiss_fft.h \
dsp/transforms/kissfft/kiss_fftr.h \
dsp/transforms/kissfft/_kiss_fft_guts.h \
dsp/wavelet/Wavelet.h \
hmm/hmm.h \
maths/Correlation.h \
maths/CosineDistance.h \
maths/Histogram.h \
maths/KLDivergence.h \
maths/MathAliases.h \
maths/MathUtilities.h \
maths/Polyfit.h \
maths/pca/pca.h \
thread/AsynchronousTask.h \
thread/BlockAllocator.h \
thread/Thread.h
SOURCES += base/Pitch.cpp \
dsp/chromagram/Chromagram.cpp \
dsp/chromagram/ChromaProcess.cpp \
dsp/chromagram/ConstantQ.cpp \
dsp/keydetection/GetKeyMode.cpp \
dsp/mfcc/MFCC.cpp \
dsp/onsets/DetectionFunction.cpp \
dsp/onsets/PeakPicking.cpp \
dsp/phasevocoder/PhaseVocoder.cpp \
dsp/rateconversion/Decimator.cpp \
dsp/rhythm/BeatSpectrum.cpp \
dsp/segmentation/cluster_melt.c \
dsp/segmentation/ClusterMeltSegmenter.cpp \
dsp/segmentation/cluster_segmenter.c \
dsp/segmentation/SavedFeatureSegmenter.cpp \
dsp/segmentation/Segmenter.cpp \
dsp/signalconditioning/DFProcess.cpp \
dsp/signalconditioning/Filter.cpp \
dsp/signalconditioning/FiltFilt.cpp \
dsp/signalconditioning/Framer.cpp \
dsp/tempotracking/DownBeat.cpp \
dsp/tempotracking/TempoTrack.cpp \
dsp/tempotracking/TempoTrackV2.cpp \
dsp/tonal/ChangeDetectionFunction.cpp \
dsp/tonal/TCSgram.cpp \
dsp/tonal/TonalEstimator.cpp \
dsp/transforms/FFT.cpp \
dsp/transforms/kissfft/kiss_fft.c \
dsp/transforms/kissfft/kiss_fftr.c \
dsp/wavelet/Wavelet.cpp \
hmm/hmm.c \
maths/Correlation.cpp \
maths/CosineDistance.cpp \
maths/KLDivergence.cpp \
maths/MathUtilities.cpp \
maths/pca/pca.c \
thread/Thread.cpp

View File

@ -0,0 +1,91 @@
QMAKE_MAC_SDK=/Developer/SDKs/MacOSX10.4u.sdk
TEMPLATE = lib
CONFIG += release warn_on staticlib x86 ppc
CONFIG -= qt
OBJECTS_DIR = tmp_obj
MOC_DIR = tmp_moc
QMAKE_CXXFLAGS_RELEASE += -O2 -g0
linux-g++:QMAKE_CXXFLAGS_RELEASE += -DNDEBUG -O3 -march=pentium4 -msse -msse2
#DEPENDPATH += base \
# dsp/chromagram \
# dsp/keydetection \
# dsp/maths \
# dsp/onsets \
# dsp/phasevocoder \
# dsp/rateconversion \
# dsp/signalconditioning \
# dsp/tempotracking \
# dsp/tonal \
# dsp/transforms
INCLUDEPATH += . include
# Input
HEADERS += base/Pitch.h \
base/Window.h \
dsp/chromagram/Chromagram.h \
dsp/chromagram/ChromaProcess.h \
dsp/chromagram/ConstantQ.h \
dsp/keydetection/GetKeyMode.h \
dsp/mfcc/MFCC.h \
dsp/onsets/DetectionFunction.h \
dsp/onsets/PeakPicking.h \
dsp/phasevocoder/PhaseVocoder.h \
dsp/rateconversion/Decimator.h \
dsp/rhythm/BeatSpectrum.h \
dsp/segmentation/cluster_melt.h \
dsp/segmentation/ClusterMeltSegmenter.h \
dsp/segmentation/cluster_segmenter.h \
dsp/segmentation/SavedFeatureSegmenter.h \
dsp/segmentation/Segmenter.h \
dsp/segmentation/segment.h \
dsp/signalconditioning/DFProcess.h \
dsp/signalconditioning/Filter.h \
dsp/signalconditioning/FiltFilt.h \
dsp/signalconditioning/Framer.h \
dsp/tempotracking/TempoTrack.h \
dsp/tonal/ChangeDetectionFunction.h \
dsp/tonal/TCSgram.h \
dsp/tonal/TonalEstimator.h \
dsp/transforms/FFT.h \
hmm/hmm.h \
maths/Correlation.h \
maths/CosineDistance.h \
maths/Histogram.h \
maths/KLDivergence.h \
maths/MathAliases.h \
maths/MathUtilities.h \
maths/Polyfit.h \
maths/pca/pca.h
SOURCES += base/Pitch.cpp \
dsp/chromagram/Chromagram.cpp \
dsp/chromagram/ChromaProcess.cpp \
dsp/chromagram/ConstantQ.cpp \
dsp/keydetection/GetKeyMode.cpp \
dsp/mfcc/MFCC.cpp \
dsp/onsets/DetectionFunction.cpp \
dsp/onsets/PeakPicking.cpp \
dsp/phasevocoder/PhaseVocoder.cpp \
dsp/rateconversion/Decimator.cpp \
dsp/rhythm/BeatSpectrum.cpp \
dsp/segmentation/cluster_melt.c \
dsp/segmentation/ClusterMeltSegmenter.cpp \
dsp/segmentation/cluster_segmenter.c \
dsp/segmentation/SavedFeatureSegmenter.cpp \
dsp/segmentation/Segmenter.cpp \
dsp/signalconditioning/DFProcess.cpp \
dsp/signalconditioning/Filter.cpp \
dsp/signalconditioning/FiltFilt.cpp \
dsp/signalconditioning/Framer.cpp \
dsp/tempotracking/TempoTrack.cpp \
dsp/tonal/ChangeDetectionFunction.cpp \
dsp/tonal/TCSgram.cpp \
dsp/tonal/TonalEstimator.cpp \
dsp/transforms/FFT.cpp \
hmm/hmm.c \
maths/Correlation.cpp \
maths/CosineDistance.cpp \
maths/KLDivergence.cpp \
maths/MathUtilities.cpp \
maths/pca/pca.c

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,181 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 <iostream>
#include <cmath>
#include "maths/MathUtilities.h"
#include "Chromagram.h"
//----------------------------------------------------------------------------
Chromagram::Chromagram( ChromaConfig Config ) :
m_skGenerated(false)
{
initialise( Config );
}
int Chromagram::initialise( ChromaConfig Config )
{
m_FMin = Config.min; // min freq
m_FMax = Config.max; // max freq
m_BPO = Config.BPO; // bins per octave
m_normalise = Config.normalise; // if frame normalisation is required
// No. of constant Q bins
m_uK = ( unsigned int ) ceil( m_BPO * log(m_FMax/m_FMin)/log(2.0));
// Create array for chroma result
m_chromadata = new double[ m_BPO ];
// Create Config Structure for ConstantQ operator
CQConfig ConstantQConfig;
// Populate CQ config structure with parameters
// inherited from the Chroma config
ConstantQConfig.FS = Config.FS;
ConstantQConfig.min = m_FMin;
ConstantQConfig.max = m_FMax;
ConstantQConfig.BPO = m_BPO;
ConstantQConfig.CQThresh = Config.CQThresh;
// Initialise ConstantQ operator
m_ConstantQ = new ConstantQ( ConstantQConfig );
// Initialise working arrays
m_frameSize = m_ConstantQ->getfftlength();
m_hopSize = m_ConstantQ->gethop();
// Initialise FFT object
m_FFT = new FFTReal(m_frameSize);
m_FFTRe = new double[ m_frameSize ];
m_FFTIm = new double[ m_frameSize ];
m_CQRe = new double[ m_uK ];
m_CQIm = new double[ m_uK ];
m_window = 0;
m_windowbuf = 0;
return 1;
}
Chromagram::~Chromagram()
{
deInitialise();
}
int Chromagram::deInitialise()
{
delete[] m_windowbuf;
delete m_window;
delete [] m_chromadata;
delete m_FFT;
delete m_ConstantQ;
delete [] m_FFTRe;
delete [] m_FFTIm;
delete [] m_CQRe;
delete [] m_CQIm;
return 1;
}
//----------------------------------------------------------------------------------
// returns the absolute value of complex number xx + i*yy
double Chromagram::kabs(double xx, double yy)
{
double ab = sqrt(xx*xx + yy*yy);
return(ab);
}
//-----------------------------------------------------------------------------------
void Chromagram::unityNormalise(double *src)
{
double min, max;
double val = 0;
MathUtilities::getFrameMinMax( src, m_BPO, & min, &max );
for( unsigned int i = 0; i < m_BPO; i++ )
{
val = src[ i ] / max;
src[ i ] = val;
}
}
double* Chromagram::process( const double *data )
{
if (!m_skGenerated) {
// Generate CQ Kernel
m_ConstantQ->sparsekernel();
m_skGenerated = true;
}
if (!m_window) {
m_window = new Window<double>(HammingWindow, m_frameSize);
m_windowbuf = new double[m_frameSize];
}
for (int i = 0; i < m_frameSize; ++i) {
m_windowbuf[i] = data[i];
}
m_window->cut(m_windowbuf);
// FFT of current frame
m_FFT->process(false, m_windowbuf, m_FFTRe, m_FFTIm);
return process(m_FFTRe, m_FFTIm);
}
double* Chromagram::process( const double *real, const double *imag )
{
if (!m_skGenerated) {
// Generate CQ Kernel
m_ConstantQ->sparsekernel();
m_skGenerated = true;
}
// initialise chromadata to 0
for (unsigned i = 0; i < m_BPO; i++) m_chromadata[i] = 0;
double cmax = 0.0;
double cval = 0;
// Calculate ConstantQ frame
m_ConstantQ->process( real, imag, m_CQRe, m_CQIm );
// add each octave of cq data into Chromagram
const unsigned octaves = (int)floor(double( m_uK/m_BPO))-1;
for (unsigned octave = 0; octave <= octaves; octave++)
{
unsigned firstBin = octave*m_BPO;
for (unsigned i = 0; i < m_BPO; i++)
{
m_chromadata[i] += kabs( m_CQRe[ firstBin + i ], m_CQIm[ firstBin + i ]);
}
}
MathUtilities::normalise(m_chromadata, m_BPO, m_normalise);
return m_chromadata;
}

View File

@ -0,0 +1,80 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 CHROMAGRAM_H
#define CHROMAGRAM_H
#include "dsp/transforms/FFT.h"
#include "base/Window.h"
#include "ConstantQ.h"
struct ChromaConfig{
unsigned int FS;
double min;
double max;
unsigned int BPO;
double CQThresh;
MathUtilities::NormaliseType normalise;
};
class Chromagram
{
public:
Chromagram( ChromaConfig Config );
~Chromagram();
double* process( const double *data ); // time domain
double* process( const double *real, const double *imag ); // frequency domain
void unityNormalise( double* src );
// Complex arithmetic
double kabs( double real, double imag );
// Results
unsigned int getK() { return m_uK;}
unsigned int getFrameSize() { return m_frameSize; }
unsigned int getHopSize() { return m_hopSize; }
private:
int initialise( ChromaConfig Config );
int deInitialise();
Window<double> *m_window;
double *m_windowbuf;
double* m_chromadata;
double m_FMin;
double m_FMax;
unsigned int m_BPO;
unsigned int m_uK;
MathUtilities::NormaliseType m_normalise;
unsigned int m_frameSize;
unsigned int m_hopSize;
FFTReal* m_FFT;
ConstantQ* m_ConstantQ;
double* m_FFTRe;
double* m_FFTIm;
double* m_CQRe;
double* m_CQIm;
bool m_skGenerated;
};
#endif

View File

@ -0,0 +1,351 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 "ConstantQ.h"
#include "dsp/transforms/FFT.h"
#include <iostream>
#ifdef NOT_DEFINED
// see note in CQprecalc
#include "CQprecalc.cpp"
static bool push_precalculated(int uk, int fftlength,
std::vector<unsigned> &is,
std::vector<unsigned> &js,
std::vector<double> &real,
std::vector<double> &imag)
{
if (uk == 76 && fftlength == 16384) {
push_76_16384(is, js, real, imag);
return true;
}
if (uk == 144 && fftlength == 4096) {
push_144_4096(is, js, real, imag);
return true;
}
if (uk == 65 && fftlength == 2048) {
push_65_2048(is, js, real, imag);
return true;
}
if (uk == 84 && fftlength == 65536) {
push_84_65536(is, js, real, imag);
return true;
}
return false;
}
#endif
//---------------------------------------------------------------------------
// nextpow2 returns the smallest integer n such that 2^n >= x.
static double nextpow2(double x) {
double y = ceil(log(x)/log(2.0));
return(y);
}
static double squaredModule(const double & xx, const double & yy) {
return xx*xx + yy*yy;
}
//----------------------------------------------------------------------------
ConstantQ::ConstantQ( CQConfig Config ) :
m_sparseKernel(0)
{
initialise( Config );
}
ConstantQ::~ConstantQ()
{
deInitialise();
}
//----------------------------------------------------------------------------
void ConstantQ::sparsekernel()
{
// std::cerr << "ConstantQ: initialising sparse kernel, uK = " << m_uK << ", FFTLength = " << m_FFTLength << "...";
SparseKernel *sk = new SparseKernel();
#ifdef NOT_DEFINED
if (push_precalculated(m_uK, m_FFTLength,
sk->is, sk->js, sk->real, sk->imag)) {
// std::cerr << "using precalculated kernel" << std::endl;
m_sparseKernel = sk;
return;
}
#endif
//generates spectral kernel matrix (upside down?)
// initialise temporal kernel with zeros, twice length to deal w. complex numbers
double* hammingWindowRe = new double [ m_FFTLength ];
double* hammingWindowIm = new double [ m_FFTLength ];
double* transfHammingWindowRe = new double [ m_FFTLength ];
double* transfHammingWindowIm = new double [ m_FFTLength ];
for (unsigned u=0; u < m_FFTLength; u++)
{
hammingWindowRe[u] = 0;
hammingWindowIm[u] = 0;
}
// Here, fftleng*2 is a guess of the number of sparse cells in the matrix
// The matrix K x fftlength but the non-zero cells are an antialiased
// square root function. So mostly is a line, with some grey point.
sk->is.reserve( m_FFTLength*2 );
sk->js.reserve( m_FFTLength*2 );
sk->real.reserve( m_FFTLength*2 );
sk->imag.reserve( m_FFTLength*2 );
// for each bin value K, calculate temporal kernel, take its fft to
//calculate the spectral kernel then threshold it to make it sparse and
//add it to the sparse kernels matrix
double squareThreshold = m_CQThresh * m_CQThresh;
FFT m_FFT(m_FFTLength);
for (unsigned k = m_uK; k--; )
{
for (unsigned u=0; u < m_FFTLength; u++)
{
hammingWindowRe[u] = 0;
hammingWindowIm[u] = 0;
}
// Computing a hamming window
const unsigned hammingLength = (int) ceil( m_dQ * m_FS / ( m_FMin * pow(2,((double)(k))/(double)m_BPO)));
unsigned origin = m_FFTLength/2 - hammingLength/2;
for (unsigned i=0; i<hammingLength; i++)
{
const double angle = 2*PI*m_dQ*i/hammingLength;
const double real = cos(angle);
const double imag = sin(angle);
const double absol = hamming(hammingLength, i)/hammingLength;
hammingWindowRe[ origin + i ] = absol*real;
hammingWindowIm[ origin + i ] = absol*imag;
}
for (unsigned i = 0; i < m_FFTLength/2; ++i) {
double temp = hammingWindowRe[i];
hammingWindowRe[i] = hammingWindowRe[i + m_FFTLength/2];
hammingWindowRe[i + m_FFTLength/2] = temp;
temp = hammingWindowIm[i];
hammingWindowIm[i] = hammingWindowIm[i + m_FFTLength/2];
hammingWindowIm[i + m_FFTLength/2] = temp;
}
//do fft of hammingWindow
m_FFT.process( 0, hammingWindowRe, hammingWindowIm, transfHammingWindowRe, transfHammingWindowIm );
for (unsigned j=0; j<( m_FFTLength ); j++)
{
// perform thresholding
const double squaredBin = squaredModule( transfHammingWindowRe[ j ], transfHammingWindowIm[ j ]);
if (squaredBin <= squareThreshold) continue;
// Insert non-zero position indexes, doubled because they are floats
sk->is.push_back(j);
sk->js.push_back(k);
// take conjugate, normalise and add to array sparkernel
sk->real.push_back( transfHammingWindowRe[ j ]/m_FFTLength);
sk->imag.push_back(-transfHammingWindowIm[ j ]/m_FFTLength);
}
}
delete [] hammingWindowRe;
delete [] hammingWindowIm;
delete [] transfHammingWindowRe;
delete [] transfHammingWindowIm;
/*
using std::cout;
using std::endl;
cout.precision(28);
int n = sk->is.size();
int w = 8;
cout << "static unsigned int sk_i_" << m_uK << "_" << m_FFTLength << "[" << n << "] = {" << endl;
for (int i = 0; i < n; ++i) {
if (i % w == 0) cout << " ";
cout << sk->is[i];
if (i + 1 < n) cout << ", ";
if (i % w == w-1) cout << endl;
};
if (n % w != 0) cout << endl;
cout << "};" << endl;
n = sk->js.size();
cout << "static unsigned int sk_j_" << m_uK << "_" << m_FFTLength << "[" << n << "] = {" << endl;
for (int i = 0; i < n; ++i) {
if (i % w == 0) cout << " ";
cout << sk->js[i];
if (i + 1 < n) cout << ", ";
if (i % w == w-1) cout << endl;
};
if (n % w != 0) cout << endl;
cout << "};" << endl;
w = 2;
n = sk->real.size();
cout << "static double sk_real_" << m_uK << "_" << m_FFTLength << "[" << n << "] = {" << endl;
for (int i = 0; i < n; ++i) {
if (i % w == 0) cout << " ";
cout << sk->real[i];
if (i + 1 < n) cout << ", ";
if (i % w == w-1) cout << endl;
};
if (n % w != 0) cout << endl;
cout << "};" << endl;
n = sk->imag.size();
cout << "static double sk_imag_" << m_uK << "_" << m_FFTLength << "[" << n << "] = {" << endl;
for (int i = 0; i < n; ++i) {
if (i % w == 0) cout << " ";
cout << sk->imag[i];
if (i + 1 < n) cout << ", ";
if (i % w == w-1) cout << endl;
};
if (n % w != 0) cout << endl;
cout << "};" << endl;
cout << "static void push_" << m_uK << "_" << m_FFTLength << "(vector<unsigned int> &is, vector<unsigned int> &js, vector<double> &real, vector<double> &imag)" << endl;
cout << "{\n is.reserve(" << n << ");\n";
cout << " js.reserve(" << n << ");\n";
cout << " real.reserve(" << n << ");\n";
cout << " imag.reserve(" << n << ");\n";
cout << " for (int i = 0; i < " << n << "; ++i) {" << endl;
cout << " is.push_back(sk_i_" << m_uK << "_" << m_FFTLength << "[i]);" << endl;
cout << " js.push_back(sk_j_" << m_uK << "_" << m_FFTLength << "[i]);" << endl;
cout << " real.push_back(sk_real_" << m_uK << "_" << m_FFTLength << "[i]);" << endl;
cout << " imag.push_back(sk_imag_" << m_uK << "_" << m_FFTLength << "[i]);" << endl;
cout << " }" << endl;
cout << "}" << endl;
*/
// std::cerr << "done\n -> is: " << sk->is.size() << ", js: " << sk->js.size() << ", reals: " << sk->real.size() << ", imags: " << sk->imag.size() << std::endl;
m_sparseKernel = sk;
return;
}
//-----------------------------------------------------------------------------
double* ConstantQ::process( const double* fftdata )
{
if (!m_sparseKernel) {
std::cerr << "ERROR: ConstantQ::process: Sparse kernel has not been initialised" << std::endl;
return m_CQdata;
}
SparseKernel *sk = m_sparseKernel;
for (unsigned row=0; row<2*m_uK; row++)
{
m_CQdata[ row ] = 0;
m_CQdata[ row+1 ] = 0;
}
const unsigned *fftbin = &(sk->is[0]);
const unsigned *cqbin = &(sk->js[0]);
const double *real = &(sk->real[0]);
const double *imag = &(sk->imag[0]);
const unsigned int sparseCells = sk->real.size();
for (unsigned i = 0; i<sparseCells; i++)
{
const unsigned row = cqbin[i];
const unsigned col = fftbin[i];
const double & r1 = real[i];
const double & i1 = imag[i];
const double & r2 = fftdata[ (2*m_FFTLength) - 2*col - 2 ];
const double & i2 = fftdata[ (2*m_FFTLength) - 2*col - 2 + 1 ];
// add the multiplication
m_CQdata[ 2*row ] += (r1*r2 - i1*i2);
m_CQdata[ 2*row+1] += (r1*i2 + i1*r2);
}
return m_CQdata;
}
void ConstantQ::initialise( CQConfig Config )
{
m_FS = Config.FS;
m_FMin = Config.min; // min freq
m_FMax = Config.max; // max freq
m_BPO = Config.BPO; // bins per octave
m_CQThresh = Config.CQThresh;// ConstantQ threshold for kernel generation
m_dQ = 1/(pow(2,(1/(double)m_BPO))-1); // Work out Q value for Filter bank
m_uK = (unsigned int) ceil(m_BPO * log(m_FMax/m_FMin)/log(2.0)); // No. of constant Q bins
// std::cerr << "ConstantQ::initialise: rate = " << m_FS << ", fmin = " << m_FMin << ", fmax = " << m_FMax << ", bpo = " << m_BPO << ", K = " << m_uK << ", Q = " << m_dQ << std::endl;
// work out length of fft required for this constant Q Filter bank
m_FFTLength = (int) pow(2, nextpow2(ceil( m_dQ*m_FS/m_FMin )));
m_hop = m_FFTLength/8; // <------ hop size is window length divided by 32
// std::cerr << "ConstantQ::initialise: -> fft length = " << m_FFTLength << ", hop = " << m_hop << std::endl;
// allocate memory for cqdata
m_CQdata = new double [2*m_uK];
}
void ConstantQ::deInitialise()
{
delete [] m_CQdata;
delete m_sparseKernel;
}
void ConstantQ::process(const double *FFTRe, const double* FFTIm,
double *CQRe, double *CQIm)
{
if (!m_sparseKernel) {
std::cerr << "ERROR: ConstantQ::process: Sparse kernel has not been initialised" << std::endl;
return;
}
SparseKernel *sk = m_sparseKernel;
for (unsigned row=0; row<m_uK; row++)
{
CQRe[ row ] = 0;
CQIm[ row ] = 0;
}
const unsigned *fftbin = &(sk->is[0]);
const unsigned *cqbin = &(sk->js[0]);
const double *real = &(sk->real[0]);
const double *imag = &(sk->imag[0]);
const unsigned int sparseCells = sk->real.size();
for (unsigned i = 0; i<sparseCells; i++)
{
const unsigned row = cqbin[i];
const unsigned col = fftbin[i];
const double & r1 = real[i];
const double & i1 = imag[i];
const double & r2 = FFTRe[ m_FFTLength - col - 1 ];
const double & i2 = FFTIm[ m_FFTLength - col - 1 ];
// add the multiplication
CQRe[ row ] += (r1*r2 - i1*i2);
CQIm[ row ] += (r1*i2 + i1*r2);
}
}

View File

@ -0,0 +1,84 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 CONSTANTQ_H
#define CONSTANTQ_H
#include <vector>
#include "maths/MathAliases.h"
#include "maths/MathUtilities.h"
struct CQConfig{
unsigned int FS; // samplerate
double min; // minimum frequency
double max; // maximum frequency
unsigned int BPO; // bins per octave
double CQThresh; // threshold
};
class ConstantQ {
//public functions incl. sparsekernel so can keep out of loop in main
public:
void process( const double* FFTRe, const double* FFTIm,
double* CQRe, double* CQIm );
ConstantQ( CQConfig Config );
~ConstantQ();
double* process( const double* FFTData );
void sparsekernel();
double hamming(int len, int n) {
double out = 0.54 - 0.46*cos(2*PI*n/len);
return(out);
}
int getnumwin() { return m_numWin;}
double getQ() { return m_dQ;}
int getK() {return m_uK ;}
int getfftlength() { return m_FFTLength;}
int gethop() { return m_hop;}
private:
void initialise( CQConfig Config );
void deInitialise();
double* m_CQdata;
unsigned int m_FS;
double m_FMin;
double m_FMax;
double m_dQ;
double m_CQThresh;
unsigned int m_numWin;
unsigned int m_hop;
unsigned int m_BPO;
unsigned int m_FFTLength;
unsigned int m_uK;
struct SparseKernel {
std::vector<unsigned> is;
std::vector<unsigned> js;
std::vector<double> imag;
std::vector<double> real;
};
SparseKernel *m_sparseKernel;
};
#endif//CONSTANTQ_H

View File

@ -0,0 +1,318 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
// GetKeyMode.cpp: implementation of the CGetKeyMode class.
//
//////////////////////////////////////////////////////////////////////
#include "GetKeyMode.h"
#include "maths/MathUtilities.h"
#include "base/Pitch.h"
#include <iostream>
#include <cstring>
#include <cstdlib>
// Chords profile
static double MajProfile[36] =
{ 0.0384, 0.0629, 0.0258, 0.0121, 0.0146, 0.0106, 0.0364, 0.0610, 0.0267,
0.0126, 0.0121, 0.0086, 0.0364, 0.0623, 0.0279, 0.0275, 0.0414, 0.0186,
0.0173, 0.0248, 0.0145, 0.0364, 0.0631, 0.0262, 0.0129, 0.0150, 0.0098,
0.0312, 0.0521, 0.0235, 0.0129, 0.0142, 0.0095, 0.0289, 0.0478, 0.0239};
static double MinProfile[36] =
{ 0.0375, 0.0682, 0.0299, 0.0119, 0.0138, 0.0093, 0.0296, 0.0543, 0.0257,
0.0292, 0.0519, 0.0246, 0.0159, 0.0234, 0.0135, 0.0291, 0.0544, 0.0248,
0.0137, 0.0176, 0.0104, 0.0352, 0.0670, 0.0302, 0.0222, 0.0349, 0.0164,
0.0174, 0.0297, 0.0166, 0.0222, 0.0401, 0.0202, 0.0175, 0.0270, 0.0146};
//
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
GetKeyMode::GetKeyMode( int sampleRate, float tuningFrequency,
double hpcpAverage, double medianAverage ) :
m_hpcpAverage( hpcpAverage ),
m_medianAverage( medianAverage ),
m_ChrPointer(0),
m_DecimatedBuffer(0),
m_ChromaBuffer(0),
m_MeanHPCP(0),
m_MajCorr(0),
m_MinCorr(0),
m_Keys(0),
m_MedianFilterBuffer(0),
m_SortedBuffer(0),
m_keyStrengths(0)
{
m_DecimationFactor = 8;
// Chromagram configuration parameters
m_ChromaConfig.normalise = MathUtilities::NormaliseUnitMax;
m_ChromaConfig.FS = lrint(sampleRate/(double)m_DecimationFactor);
if (m_ChromaConfig.FS < 1) m_ChromaConfig.FS = 1;
// Set C (= MIDI #12) as our base :
// This implies that key = 1 => Cmaj, key = 12 => Bmaj, key = 13 => Cmin, etc.
m_ChromaConfig.min = Pitch::getFrequencyForPitch
(48, 0, tuningFrequency);
m_ChromaConfig.max = Pitch::getFrequencyForPitch
(96, 0, tuningFrequency);
m_ChromaConfig.BPO = 36;
m_ChromaConfig.CQThresh = 0.0054;
// Chromagram inst.
m_Chroma = new Chromagram( m_ChromaConfig );
// Get calculated parameters from chroma object
m_ChromaFrameSize = m_Chroma->getFrameSize();
// override hopsize for this application
m_ChromaHopSize = m_ChromaFrameSize;
m_BPO = m_ChromaConfig.BPO;
// std::cerr << "chroma frame size = " << m_ChromaFrameSize << ", decimation factor = " << m_DecimationFactor << " therefore block size = " << getBlockSize() << std::endl;
// Chromagram average and estimated key median filter lengths
m_ChromaBuffersize = (int)ceil( m_hpcpAverage * m_ChromaConfig.FS/m_ChromaFrameSize );
m_MedianWinsize = (int)ceil( m_medianAverage * m_ChromaConfig.FS/m_ChromaFrameSize );
// Reset counters
m_bufferindex = 0;
m_ChromaBufferFilling = 0;
m_MedianBufferFilling = 0;
// Spawn objectc/arrays
m_DecimatedBuffer = new double[m_ChromaFrameSize];
m_ChromaBuffer = new double[m_BPO * m_ChromaBuffersize];
memset( m_ChromaBuffer, 0, sizeof(double) * m_BPO * m_ChromaBuffersize);
m_MeanHPCP = new double[m_BPO];
m_MajCorr = new double[m_BPO];
m_MinCorr = new double[m_BPO];
m_Keys = new double[2*m_BPO];
m_MedianFilterBuffer = new int[ m_MedianWinsize ];
memset( m_MedianFilterBuffer, 0, sizeof(int)*m_MedianWinsize);
m_SortedBuffer = new int[ m_MedianWinsize ];
memset( m_SortedBuffer, 0, sizeof(int)*m_MedianWinsize);
m_Decimator = new Decimator
( m_ChromaFrameSize*m_DecimationFactor, m_DecimationFactor );
m_keyStrengths = new double[24];
}
GetKeyMode::~GetKeyMode()
{
delete m_Chroma;
delete m_Decimator;
delete [] m_DecimatedBuffer;
delete [] m_ChromaBuffer;
delete [] m_MeanHPCP;
delete [] m_MajCorr;
delete [] m_MinCorr;
delete [] m_Keys;
delete [] m_MedianFilterBuffer;
delete [] m_SortedBuffer;
delete[] m_keyStrengths;
}
double GetKeyMode::krumCorr(double *pData1, double *pData2, unsigned int length)
{
double retVal= 0.0;
double num = 0;
double den = 0;
double mX = MathUtilities::mean( pData1, length );
double mY = MathUtilities::mean( pData2, length );
double sum1 = 0;
double sum2 = 0;
for( unsigned int i = 0; i <length; i++ )
{
num += ( pData1[i] - mX ) * ( pData2[i] - mY );
sum1 += ( (pData1[i]-mX) * (pData1[i]-mX) );
sum2 += ( (pData2[i]-mY) * (pData2[i]-mY) );
}
den = sqrt(sum1 * sum2);
if( den>0 )
retVal = num/den;
else
retVal = 0;
return retVal;
}
int GetKeyMode::process(double *PCMData)
{
int key;
unsigned int j,k;
//////////////////////////////////////////////
m_Decimator->process( PCMData, m_DecimatedBuffer);
m_ChrPointer = m_Chroma->process( m_DecimatedBuffer );
// Move bins such that the centre of the base note is in the
// middle of its three bins :
// Added 21.11.07 by Chris Sutton based on debugging with Katy
// Noland + comparison with Matlab equivalent.
MathUtilities::circShift( m_ChrPointer, m_BPO, 1);
/*
std::cout << "raw chroma: ";
for (int ii = 0; ii < m_BPO; ++ii) {
if (ii % (m_BPO/12) == 0) std::cout << "\n";
std::cout << m_ChrPointer[ii] << " ";
}
std::cout << std::endl;
*/
// populate hpcp values;
int cbidx;
for( j = 0; j < m_BPO; j++ )
{
cbidx = (m_bufferindex * m_BPO) + j;
m_ChromaBuffer[ cbidx ] = m_ChrPointer[j];
}
//keep track of input buffers;
if( m_bufferindex++ >= m_ChromaBuffersize - 1)
m_bufferindex = 0;
// track filling of chroma matrix
if( m_ChromaBufferFilling++ >= m_ChromaBuffersize)
m_ChromaBufferFilling = m_ChromaBuffersize;
//calculate mean
for( k = 0; k < m_BPO; k++ )
{
double mnVal = 0.0;
for( j = 0; j < m_ChromaBufferFilling; j++ )
{
mnVal += m_ChromaBuffer[ k + (j*m_BPO) ];
}
m_MeanHPCP[k] = mnVal/(double)m_ChromaBufferFilling;
}
for( k = 0; k < m_BPO; k++ )
{
m_MajCorr[k] = krumCorr( m_MeanHPCP, MajProfile, m_BPO );
m_MinCorr[k] = krumCorr( m_MeanHPCP, MinProfile, m_BPO );
MathUtilities::circShift( MajProfile, m_BPO, 1 );
MathUtilities::circShift( MinProfile, m_BPO, 1 );
}
for( k = 0; k < m_BPO; k++ )
{
m_Keys[k] = m_MajCorr[k];
m_Keys[k+m_BPO] = m_MinCorr[k];
}
for (k = 0; k < 24; ++k) {
m_keyStrengths[k] = 0;
}
for( k = 0; k < m_BPO*2; k++ )
{
int idx = k / (m_BPO/12);
int rem = k % (m_BPO/12);
if (rem == 0 || m_Keys[k] > m_keyStrengths[idx]) {
m_keyStrengths[idx] = m_Keys[k];
}
// m_keyStrengths[k/(m_BPO/12)] += m_Keys[k];
}
/*
std::cout << "raw keys: ";
for (int ii = 0; ii < 2*m_BPO; ++ii) {
if (ii % (m_BPO/12) == 0) std::cout << "\n";
std::cout << m_Keys[ii] << " ";
}
std::cout << std::endl;
std::cout << "key strengths: ";
for (int ii = 0; ii < 24; ++ii) {
if (ii % 6 == 0) std::cout << "\n";
std::cout << m_keyStrengths[ii] << " ";
}
std::cout << std::endl;
*/
double dummy;
// '1 +' because we number keys 1-24, not 0-23.
key = 1 + (int)ceil( (double)MathUtilities::getMax( m_Keys, 2* m_BPO, &dummy )/3 );
// std::cout << "key pre-sorting: " << key << std::endl;
//Median filtering
// track Median buffer initial filling
if( m_MedianBufferFilling++ >= m_MedianWinsize)
m_MedianBufferFilling = m_MedianWinsize;
//shift median buffer
for( k = 1; k < m_MedianWinsize; k++ )
{
m_MedianFilterBuffer[ k - 1 ] = m_MedianFilterBuffer[ k ];
}
//write new key value into median buffer
m_MedianFilterBuffer[ m_MedianWinsize - 1 ] = key;
//Copy median into sorting buffer, reversed
unsigned int ijx = 0;
for( k = 0; k < m_MedianWinsize; k++ )
{
m_SortedBuffer[k] = m_MedianFilterBuffer[m_MedianWinsize-1-ijx];
ijx++;
}
qsort(m_SortedBuffer, m_MedianBufferFilling, sizeof(unsigned int),
MathUtilities::compareInt);
/*
std::cout << "sorted: ";
for (int ii = 0; ii < m_MedianBufferFilling; ++ii) {
std::cout << m_SortedBuffer[ii] << " ";
}
std::cout << std::endl;
*/
int sortlength = m_MedianBufferFilling;
int midpoint = (int)ceil((double)sortlength/2);
// std::cout << "midpoint = " << midpoint << endl;
if( midpoint <= 0 )
midpoint = 1;
key = m_SortedBuffer[midpoint-1];
// std::cout << "returning key = " << key << endl;
return key;
}
bool GetKeyMode::isModeMinor( int key )
{
return (key > 12);
}

View File

@ -0,0 +1,96 @@
/*
* Author: c.landone
* Description:
*
* Syntax: C++
*
* Copyright (c) 2005 Centre for Digital Music ( C4DM )
* Queen Mary Univesrity of London
*
*
* This program is not free software; you cannot redistribute it
* without the explicit authorization from the centre for digital music,
* queen mary university of london
*
*/
#ifndef GETKEYMODE_H
#define GETKEYMODE_H
#include "dsp/rateconversion/Decimator.h"
#include "dsp/chromagram/Chromagram.h"
class GetKeyMode
{
public:
GetKeyMode( int sampleRate, float tuningFrequency,
double hpcpAverage, double medianAverage );
virtual ~GetKeyMode();
int process( double* PCMData );
double krumCorr( double* pData1, double* pData2, unsigned int length );
unsigned int getBlockSize() { return m_ChromaFrameSize*m_DecimationFactor; }
unsigned int getHopSize() { return m_ChromaHopSize*m_DecimationFactor; }
double* getChroma() { return m_ChrPointer; }
unsigned int getChromaSize() { return m_BPO; }
double* getMeanHPCP() { return m_MeanHPCP; }
double *getKeyStrengths() { return m_keyStrengths; }
bool isModeMinor( int key );
protected:
double m_hpcpAverage;
double m_medianAverage;
unsigned int m_DecimationFactor;
//Decimator (fixed)
Decimator* m_Decimator;
//chroma configuration
ChromaConfig m_ChromaConfig;
//Chromagram object
Chromagram* m_Chroma;
//Chromagram output pointer
double* m_ChrPointer;
//Framesize
unsigned int m_ChromaFrameSize;
//Hop
unsigned int m_ChromaHopSize;
//Bins per octave
unsigned int m_BPO;
unsigned int m_ChromaBuffersize;
unsigned int m_MedianWinsize;
unsigned int m_bufferindex;
unsigned int m_ChromaBufferFilling;
unsigned int m_MedianBufferFilling;
double* m_DecimatedBuffer;
double* m_ChromaBuffer;
double* m_MeanHPCP;
double* m_MajCorr;
double* m_MinCorr;
double* m_Keys;
int* m_MedianFilterBuffer;
int* m_SortedBuffer;
double *m_keyStrengths;
};
#endif // !defined GETKEYMODE_H

View File

@ -0,0 +1,276 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2005 Nicolas Chetry, copyright 2008 QMUL.
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 <cmath>
#include <cstdlib>
#include <cstring>
#include "MFCC.h"
#include "dsp/transforms/FFT.h"
#include "base/Window.h"
MFCC::MFCC(MFCCConfig config)
{
int i,j;
/* Calculate at startup */
double *freqs, *lower, *center, *upper, *triangleHeight, *fftFreqs;
lowestFrequency = 66.6666666;
linearFilters = 13;
linearSpacing = 66.66666666;
logFilters = 27;
logSpacing = 1.0711703;
/* FFT and analysis window sizes */
fftSize = config.fftsize;
fft = new FFTReal(fftSize);
totalFilters = linearFilters + logFilters;
logPower = config.logpower;
samplingRate = config.FS;
/* The number of cepstral componenents */
nceps = config.nceps;
/* Set if user want C0 */
WANT_C0 = (config.want_c0 ? 1 : 0);
/* Allocate space for feature vector */
if (WANT_C0 == 1) {
ceps = (double*)calloc(nceps+1, sizeof(double));
} else {
ceps = (double*)calloc(nceps, sizeof(double));
}
/* Allocate space for local vectors */
mfccDCTMatrix = (double**)calloc(nceps+1, sizeof(double*));
for (i = 0; i < nceps+1; i++) {
mfccDCTMatrix[i]= (double*)calloc(totalFilters, sizeof(double));
}
mfccFilterWeights = (double**)calloc(totalFilters, sizeof(double*));
for (i = 0; i < totalFilters; i++) {
mfccFilterWeights[i] = (double*)calloc(fftSize, sizeof(double));
}
freqs = (double*)calloc(totalFilters+2,sizeof(double));
lower = (double*)calloc(totalFilters,sizeof(double));
center = (double*)calloc(totalFilters,sizeof(double));
upper = (double*)calloc(totalFilters,sizeof(double));
triangleHeight = (double*)calloc(totalFilters,sizeof(double));
fftFreqs = (double*)calloc(fftSize,sizeof(double));
for (i = 0; i < linearFilters; i++) {
freqs[i] = lowestFrequency + ((double)i) * linearSpacing;
}
for (i = linearFilters; i < totalFilters+2; i++) {
freqs[i] = freqs[linearFilters-1] *
pow(logSpacing, (double)(i-linearFilters+1));
}
/* Define lower, center and upper */
memcpy(lower, freqs,totalFilters*sizeof(double));
memcpy(center, &freqs[1],totalFilters*sizeof(double));
memcpy(upper, &freqs[2],totalFilters*sizeof(double));
for (i=0;i<totalFilters;i++){
triangleHeight[i] = 2./(upper[i]-lower[i]);
}
for (i=0;i<fftSize;i++){
fftFreqs[i] = ((double) i / ((double) fftSize ) *
(double) samplingRate);
}
/* Build now the mccFilterWeight matrix */
for (i=0;i<totalFilters;i++){
for (j=0;j<fftSize;j++) {
if ((fftFreqs[j] > lower[i]) && (fftFreqs[j] <= center[i])) {
mfccFilterWeights[i][j] = triangleHeight[i] *
(fftFreqs[j]-lower[i]) / (center[i]-lower[i]);
}
else
{
mfccFilterWeights[i][j] = 0.0;
}
if ((fftFreqs[j]>center[i]) && (fftFreqs[j]<upper[i])) {
mfccFilterWeights[i][j] = mfccFilterWeights[i][j]
+ triangleHeight[i] * (upper[i]-fftFreqs[j])
/ (upper[i]-center[i]);
}
else
{
mfccFilterWeights[i][j] = mfccFilterWeights[i][j] + 0.0;
}
}
}
/*
* We calculate now mfccDCT matrix
* NB: +1 because of the DC component
*/
const double pi = 3.14159265358979323846264338327950288;
for (i = 0; i < nceps+1; i++) {
for (j = 0; j < totalFilters; j++) {
mfccDCTMatrix[i][j] = (1./sqrt((double) totalFilters / 2.))
* cos((double) i * ((double) j + 0.5) / (double) totalFilters * pi);
}
}
for (j = 0; j < totalFilters; j++){
mfccDCTMatrix[0][j] = (sqrt(2.)/2.) * mfccDCTMatrix[0][j];
}
/* The analysis window */
window = new Window<double>(config.window, fftSize);
/* Allocate memory for the FFT */
realOut = (double*)calloc(fftSize, sizeof(double));
imagOut = (double*)calloc(fftSize, sizeof(double));
earMag = (double*)calloc(totalFilters, sizeof(double));
fftMag = (double*)calloc(fftSize/2, sizeof(double));
free(freqs);
free(lower);
free(center);
free(upper);
free(triangleHeight);
free(fftFreqs);
}
MFCC::~MFCC()
{
int i;
/* Free the structure */
for (i = 0; i < nceps+1; i++) {
free(mfccDCTMatrix[i]);
}
free(mfccDCTMatrix);
for (i = 0; i < totalFilters; i++) {
free(mfccFilterWeights[i]);
}
free(mfccFilterWeights);
/* Free the feature vector */
free(ceps);
/* The analysis window */
delete window;
free(earMag);
free(fftMag);
/* Free the FFT */
free(realOut);
free(imagOut);
delete fft;
}
/*
*
* Extract the MFCC on the input frame
*
*/
int MFCC::process(const double *inframe, double *outceps)
{
double *inputData = (double *)malloc(fftSize * sizeof(double));
for (int i = 0; i < fftSize; ++i) inputData[i] = inframe[i];
window->cut(inputData);
/* Calculate the fft on the input frame */
fft->process(0, inputData, realOut, imagOut);
free(inputData);
return process(realOut, imagOut, outceps);
}
int MFCC::process(const double *real, const double *imag, double *outceps)
{
int i, j;
for (i = 0; i < fftSize/2; ++i) {
fftMag[i] = sqrt(real[i] * real[i] + imag[i] * imag[i]);
}
for (i = 0; i < totalFilters; ++i) {
earMag[i] = 0.0;
}
/* Multiply by mfccFilterWeights */
for (i = 0; i < totalFilters; i++) {
double tmp = 0.0;
for (j = 0; j < fftSize/2; j++) {
tmp = tmp + (mfccFilterWeights[i][j] * fftMag[j]);
}
if (tmp > 0) earMag[i] = log10(tmp);
else earMag[i] = 0.0;
if (logPower != 1.0) {
earMag[i] = pow(earMag[i], logPower);
}
}
/*
*
* Calculate now the cepstral coefficients
* with or without the DC component
*
*/
if (WANT_C0 == 1) {
for (i = 0; i < nceps+1; i++) {
double tmp = 0.;
for (j = 0; j < totalFilters; j++){
tmp = tmp + mfccDCTMatrix[i][j] * earMag[j];
}
outceps[i] = tmp;
}
}
else
{
for (i = 1; i < nceps+1; i++) {
double tmp = 0.;
for (j = 0; j < totalFilters; j++){
tmp = tmp + mfccDCTMatrix[i][j] * earMag[j];
}
outceps[i-1] = tmp;
}
}
return nceps;
}

View File

@ -0,0 +1,98 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2005 Nicolas Chetry, copyright 2008 QMUL.
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 MFCC_H
#define MFCC_H
#include "base/Window.h"
class FFTReal;
struct MFCCConfig {
int FS;
int fftsize;
int nceps;
double logpower;
bool want_c0;
WindowType window;
MFCCConfig(int _FS) :
FS(_FS), fftsize(2048), nceps(19),
logpower(1.0), want_c0(true), window(HammingWindow) { }
};
class MFCC
{
public:
MFCC(MFCCConfig config);
virtual ~MFCC();
/**
* Process time-domain input data. inframe must contain
* getfftlength() samples. outceps must contain space for nceps
* values, plus one if want_c0 is specified.
*/
int process(const double *inframe, double *outceps);
/**
* Process time-domain input data. real and imag must contain
* getfftlength()/2+1 elements (i.e. the conjugate half of the FFT
* is not expected). outceps must contain space for nceps values,
* plus one if want_c0 is specified.
*/
int process(const double *real, const double *imag, double *outceps);
int getfftlength() const { return fftSize; }
private:
/* Filter bank parameters */
double lowestFrequency;
int linearFilters;
double linearSpacing;
int logFilters;
double logSpacing;
/* FFT length */
int fftSize;
int totalFilters;
double logPower;
/* Misc. */
int samplingRate;
int nceps;
/* MFCC vector */
double *ceps;
double **mfccDCTMatrix;
double **mfccFilterWeights;
/* The analysis window */
Window<double> *window;
/* For the FFT */
double *realOut;
double *imagOut;
double *fftMag;
double *earMag;
FFTReal *fft;
/* Set if user want C0 */
int WANT_C0;
};
#endif

View File

@ -0,0 +1,296 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 "DetectionFunction.h"
#include <cstring>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
DetectionFunction::DetectionFunction( DFConfig Config ) :
m_window(0)
{
m_magHistory = NULL;
m_phaseHistory = NULL;
m_phaseHistoryOld = NULL;
m_magPeaks = NULL;
initialise( Config );
}
DetectionFunction::~DetectionFunction()
{
deInitialise();
}
void DetectionFunction::initialise( DFConfig Config )
{
m_dataLength = Config.frameLength;
m_halfLength = m_dataLength/2;
m_DFType = Config.DFType;
m_stepSize = Config.stepSize;
m_whiten = Config.adaptiveWhitening;
m_whitenRelaxCoeff = Config.whiteningRelaxCoeff;
m_whitenFloor = Config.whiteningFloor;
if (m_whitenRelaxCoeff < 0) m_whitenRelaxCoeff = 0.9997;
if (m_whitenFloor < 0) m_whitenFloor = 0.01;
m_magHistory = new double[ m_halfLength ];
memset(m_magHistory,0, m_halfLength*sizeof(double));
m_phaseHistory = new double[ m_halfLength ];
memset(m_phaseHistory,0, m_halfLength*sizeof(double));
m_phaseHistoryOld = new double[ m_halfLength ];
memset(m_phaseHistoryOld,0, m_halfLength*sizeof(double));
m_magPeaks = new double[ m_halfLength ];
memset(m_magPeaks,0, m_halfLength*sizeof(double));
// See note in process(const double *) below
int actualLength = MathUtilities::previousPowerOfTwo(m_dataLength);
m_phaseVoc = new PhaseVocoder(actualLength);
m_DFWindowedFrame = new double[ m_dataLength ];
m_magnitude = new double[ m_halfLength ];
m_thetaAngle = new double[ m_halfLength ];
m_window = new Window<double>(HanningWindow, m_dataLength);
}
void DetectionFunction::deInitialise()
{
delete [] m_magHistory ;
delete [] m_phaseHistory ;
delete [] m_phaseHistoryOld ;
delete [] m_magPeaks ;
delete m_phaseVoc;
delete [] m_DFWindowedFrame;
delete [] m_magnitude;
delete [] m_thetaAngle;
delete m_window;
}
double DetectionFunction::process( const double *TDomain )
{
m_window->cut( TDomain, m_DFWindowedFrame );
// Our own FFT implementation supports power-of-two sizes only.
// If we have to use this implementation (as opposed to the
// version of process() below that operates on frequency domain
// data directly), we will have to use the next smallest power of
// two from the block size. Results may vary accordingly!
int actualLength = MathUtilities::previousPowerOfTwo(m_dataLength);
if (actualLength != m_dataLength) {
// Pre-fill mag and phase vectors with zero, as the FFT output
// will not fill the arrays
for (int i = actualLength/2; i < m_dataLength/2; ++i) {
m_magnitude[i] = 0;
m_thetaAngle[0] = 0;
}
}
m_phaseVoc->process(m_DFWindowedFrame, m_magnitude, m_thetaAngle);
if (m_whiten) whiten();
return runDF();
}
double DetectionFunction::process( const double *magnitudes, const double *phases )
{
for (size_t i = 0; i < m_halfLength; ++i) {
m_magnitude[i] = magnitudes[i];
m_thetaAngle[i] = phases[i];
}
if (m_whiten) whiten();
return runDF();
}
void DetectionFunction::whiten()
{
for (unsigned int i = 0; i < m_halfLength; ++i) {
double m = m_magnitude[i];
if (m < m_magPeaks[i]) {
m = m + (m_magPeaks[i] - m) * m_whitenRelaxCoeff;
}
if (m < m_whitenFloor) m = m_whitenFloor;
m_magPeaks[i] = m;
m_magnitude[i] /= m;
}
}
double DetectionFunction::runDF()
{
double retVal = 0;
switch( m_DFType )
{
case DF_HFC:
retVal = HFC( m_halfLength, m_magnitude);
break;
case DF_SPECDIFF:
retVal = specDiff( m_halfLength, m_magnitude);
break;
case DF_PHASEDEV:
retVal = phaseDev( m_halfLength, m_thetaAngle);
break;
case DF_COMPLEXSD:
retVal = complexSD( m_halfLength, m_magnitude, m_thetaAngle);
break;
case DF_BROADBAND:
retVal = broadband( m_halfLength, m_magnitude);
break;
}
return retVal;
}
double DetectionFunction::HFC(unsigned int length, double *src)
{
unsigned int i;
double val = 0;
for( i = 0; i < length; i++)
{
val += src[ i ] * ( i + 1);
}
return val;
}
double DetectionFunction::specDiff(unsigned int length, double *src)
{
unsigned int i;
double val = 0.0;
double temp = 0.0;
double diff = 0.0;
for( i = 0; i < length; i++)
{
temp = fabs( (src[ i ] * src[ i ]) - (m_magHistory[ i ] * m_magHistory[ i ]) );
diff= sqrt(temp);
// (See note in phaseDev below.)
val += diff;
m_magHistory[ i ] = src[ i ];
}
return val;
}
double DetectionFunction::phaseDev(unsigned int length, double *srcPhase)
{
unsigned int i;
double tmpPhase = 0;
double tmpVal = 0;
double val = 0;
double dev = 0;
for( i = 0; i < length; i++)
{
tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
dev = MathUtilities::princarg( tmpPhase );
// A previous version of this code only counted the value here
// if the magnitude exceeded 0.1. My impression is that
// doesn't greatly improve the results for "loud" music (so
// long as the peak picker is reasonably sophisticated), but
// does significantly damage its ability to work with quieter
// music, so I'm removing it and counting the result always.
// Same goes for the spectral difference measure above.
tmpVal = fabs(dev);
val += tmpVal ;
m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
m_phaseHistory[ i ] = srcPhase[ i ];
}
return val;
}
double DetectionFunction::complexSD(unsigned int length, double *srcMagnitude, double *srcPhase)
{
unsigned int i;
double val = 0;
double tmpPhase = 0;
double tmpReal = 0;
double tmpImag = 0;
double dev = 0;
ComplexData meas = ComplexData( 0, 0 );
ComplexData j = ComplexData( 0, 1 );
for( i = 0; i < length; i++)
{
tmpPhase = (srcPhase[ i ]- 2*m_phaseHistory[ i ]+m_phaseHistoryOld[ i ]);
dev= MathUtilities::princarg( tmpPhase );
meas = m_magHistory[i] - ( srcMagnitude[ i ] * exp( j * dev) );
tmpReal = real( meas );
tmpImag = imag( meas );
val += sqrt( (tmpReal * tmpReal) + (tmpImag * tmpImag) );
m_phaseHistoryOld[ i ] = m_phaseHistory[ i ] ;
m_phaseHistory[ i ] = srcPhase[ i ];
m_magHistory[ i ] = srcMagnitude[ i ];
}
return val;
}
double DetectionFunction::broadband(unsigned int length, double *src)
{
double val = 0;
for (unsigned int i = 0; i < length; ++i) {
double sqrmag = src[i] * src[i];
if (m_magHistory[i] > 0.0) {
double diff = 10.0 * log10(sqrmag / m_magHistory[i]);
if (diff > m_dbRise) val = val + 1;
}
m_magHistory[i] = sqrmag;
}
return val;
}
double* DetectionFunction::getSpectrumMagnitude()
{
return m_magnitude;
}

View File

@ -0,0 +1,85 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 DETECTIONFUNCTION_H
#define DETECTIONFUNCTION_H
#include "maths/MathUtilities.h"
#include "maths/MathAliases.h"
#include "dsp/phasevocoder/PhaseVocoder.h"
#include "base/Window.h"
#define DF_HFC (1)
#define DF_SPECDIFF (2)
#define DF_PHASEDEV (3)
#define DF_COMPLEXSD (4)
#define DF_BROADBAND (5)
struct DFConfig{
unsigned int stepSize; // DF step in samples
unsigned int frameLength; // DF analysis window - usually 2*step
int DFType; // type of detection function ( see defines )
double dbRise; // only used for broadband df (and required for it)
bool adaptiveWhitening; // perform adaptive whitening
double whiteningRelaxCoeff; // if < 0, a sensible default will be used
double whiteningFloor; // if < 0, a sensible default will be used
};
class DetectionFunction
{
public:
double* getSpectrumMagnitude();
DetectionFunction( DFConfig Config );
virtual ~DetectionFunction();
double process( const double* TDomain );
double process( const double* magnitudes, const double* phases );
private:
void whiten();
double runDF();
double HFC( unsigned int length, double* src);
double specDiff( unsigned int length, double* src);
double phaseDev(unsigned int length, double *srcPhase);
double complexSD(unsigned int length, double *srcMagnitude, double *srcPhase);
double broadband(unsigned int length, double *srcMagnitude);
private:
void initialise( DFConfig Config );
void deInitialise();
int m_DFType;
unsigned int m_dataLength;
unsigned int m_halfLength;
unsigned int m_stepSize;
double m_dbRise;
bool m_whiten;
double m_whitenRelaxCoeff;
double m_whitenFloor;
double* m_magHistory;
double* m_phaseHistory;
double* m_phaseHistoryOld;
double* m_magPeaks;
double* m_DFWindowedFrame; // Array for windowed analysis frame
double* m_magnitude; // Magnitude of analysis frame ( frequency domain )
double* m_thetaAngle;// Phase of analysis frame ( frequency domain )
Window<double> *m_window;
PhaseVocoder* m_phaseVoc; // Phase Vocoder
};
#endif

View File

@ -0,0 +1,148 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 "PeakPicking.h"
#include "maths/Polyfit.h"
#include <iostream>
#include <cstring>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
PeakPicking::PeakPicking( PPickParams Config )
{
m_workBuffer = NULL;
initialise( Config );
}
PeakPicking::~PeakPicking()
{
deInitialise();
}
void PeakPicking::initialise( PPickParams Config )
{
m_DFLength = Config.length ;
Qfilta = Config.QuadThresh.a ;
Qfiltb = Config.QuadThresh.b ;
Qfiltc = Config.QuadThresh.c ;
m_DFProcessingParams.length = m_DFLength;
m_DFProcessingParams.LPOrd = Config.LPOrd;
m_DFProcessingParams.LPACoeffs = Config.LPACoeffs;
m_DFProcessingParams.LPBCoeffs = Config.LPBCoeffs;
m_DFProcessingParams.winPre = Config.WinT.pre;
m_DFProcessingParams.winPost = Config.WinT.post;
m_DFProcessingParams.AlphaNormParam = Config.alpha;
m_DFProcessingParams.isMedianPositive = false;
m_DFSmoothing = new DFProcess( m_DFProcessingParams );
m_workBuffer = new double[ m_DFLength ];
memset( m_workBuffer, 0, sizeof(double)*m_DFLength);
}
void PeakPicking::deInitialise()
{
delete [] m_workBuffer;
delete m_DFSmoothing;
m_workBuffer = NULL;
}
void PeakPicking::process( double* src, unsigned int len, vector<int> &onsets )
{
if (len < 4) return;
vector <double> m_maxima;
// Signal conditioning
m_DFSmoothing->process( src, m_workBuffer );
for( unsigned int u = 0; u < len; u++)
{
m_maxima.push_back( m_workBuffer[ u ] );
}
quadEval( m_maxima, onsets );
for( int b = 0; b < m_maxima.size(); b++)
{
src[ b ] = m_maxima[ b ];
}
}
int PeakPicking::quadEval( vector<double> &src, vector<int> &idx )
{
unsigned int maxLength;
vector <int> m_maxIndex;
vector <int> m_onsetPosition;
vector <double> m_maxFit;
vector <double> m_poly;
vector <double> m_err;
double p;
m_poly.push_back(0);
m_poly.push_back(0);
m_poly.push_back(0);
for( int t = -2; t < 3; t++)
{
m_err.push_back( (double)t );
}
for( unsigned int i = 2; i < src.size() - 2; i++)
{
if( (src[i] > src[i-1]) && (src[i] > src[i+1]) && (src[i] > 0) )
{
// m_maxIndex.push_back( i + 1 );
m_maxIndex.push_back(i);
}
}
maxLength = m_maxIndex.size();
double selMax = 0;
for( unsigned int j = 0; j < maxLength ; j++)
{
for (int k = -2; k <= 2; ++k)
{
selMax = src[ m_maxIndex[j] + k ] ;
m_maxFit.push_back(selMax);
}
p = TPolyFit::PolyFit2( m_err, m_maxFit, m_poly);
double f = m_poly[0];
double g = m_poly[1];
double h = m_poly[2];
int kk = m_poly.size();
if (h < -Qfilta || f > Qfiltc)
{
idx.push_back(m_maxIndex[j]);
}
m_maxFit.clear();
}
return 1;
}

View File

@ -0,0 +1,81 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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.
*/
// PeakPicking.h: interface for the PeakPicking class.
//
//////////////////////////////////////////////////////////////////////
#ifndef PEAKPICKING_H
#define PEAKPICKING_H
#include "maths/MathUtilities.h"
#include "maths/MathAliases.h"
#include "dsp/signalconditioning/DFProcess.h"
struct PPWinThresh
{
unsigned int pre;
unsigned int post;
};
struct QFitThresh
{
double a;
double b;
double c;
};
struct PPickParams
{
unsigned int length; //Detection FunctionLength
double tau; // time resolution of the detection function:
unsigned int alpha; //alpha-norm parameter
double cutoff;//low-pass Filter cutoff freq
unsigned int LPOrd; // low-pass Filter order
double* LPACoeffs; //low pass Filter den coefficients
double* LPBCoeffs; //low pass Filter num coefficients
PPWinThresh WinT;//window size in frames for adaptive thresholding [pre post]:
QFitThresh QuadThresh;
};
class PeakPicking
{
public:
PeakPicking( PPickParams Config );
virtual ~PeakPicking();
void process( double* src, unsigned int len, vector<int> &onsets );
private:
void initialise( PPickParams Config );
void deInitialise();
int quadEval( vector<double> &src, vector<int> &idx );
DFProcConfig m_DFProcessingParams;
unsigned int m_DFLength ;
double Qfilta ;
double Qfiltb;
double Qfiltc;
double* m_workBuffer;
DFProcess* m_DFSmoothing;
};
#endif

View File

@ -0,0 +1,79 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 "PhaseVocoder.h"
#include "dsp/transforms/FFT.h"
#include <math.h>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
PhaseVocoder::PhaseVocoder(unsigned int n) :
m_n(n)
{
m_fft = new FFTReal(m_n);
m_realOut = new double[m_n];
m_imagOut = new double[m_n];
}
PhaseVocoder::~PhaseVocoder()
{
delete [] m_realOut;
delete [] m_imagOut;
delete m_fft;
}
void PhaseVocoder::FFTShift(unsigned int size, double *src)
{
const int hs = size/2;
for (int i = 0; i < hs; ++i) {
double tmp = src[i];
src[i] = src[i + hs];
src[i + hs] = tmp;
}
}
void PhaseVocoder::process(double *src, double *mag, double *theta)
{
FFTShift( m_n, src);
m_fft->process(0, src, m_realOut, m_imagOut);
getMagnitude( m_n/2, mag, m_realOut, m_imagOut);
getPhase( m_n/2, theta, m_realOut, m_imagOut);
}
void PhaseVocoder::getMagnitude(unsigned int size, double *mag, double *real, double *imag)
{
unsigned int j;
for( j = 0; j < size; j++)
{
mag[ j ] = sqrt( real[ j ] * real[ j ] + imag[ j ] * imag[ j ]);
}
}
void PhaseVocoder::getPhase(unsigned int size, double *theta, double *real, double *imag)
{
unsigned int k;
// Phase Angle "matlab" style
//Watch out for quadrant mapping !!!
for( k = 0; k < size; k++)
{
theta[ k ] = atan2( -imag[ k ], real[ k ]);
}
}

View File

@ -0,0 +1,42 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 PHASEVOCODER_H
#define PHASEVOCODER_H
class FFTReal;
class PhaseVocoder
{
public:
PhaseVocoder( unsigned int size );
virtual ~PhaseVocoder();
void process( double* src, double* mag, double* theta);
protected:
void getPhase(unsigned int size, double *theta, double *real, double *imag);
// void coreFFT( unsigned int NumSamples, double *RealIn, double* ImagIn, double *RealOut, double *ImagOut);
void getMagnitude( unsigned int size, double* mag, double* real, double* imag);
void FFTShift( unsigned int size, double* src);
unsigned int m_n;
FFTReal *m_fft;
double *m_imagOut;
double *m_realOut;
};
#endif

View File

@ -0,0 +1,226 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 "Decimator.h"
#include <iostream>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Decimator::Decimator( unsigned int inLength, unsigned int decFactor )
{
m_inputLength = 0;
m_outputLength = 0;
m_decFactor = 1;
initialise( inLength, decFactor );
}
Decimator::~Decimator()
{
deInitialise();
}
void Decimator::initialise( unsigned int inLength, unsigned int decFactor)
{
m_inputLength = inLength;
m_decFactor = decFactor;
m_outputLength = m_inputLength / m_decFactor;
decBuffer = new double[ m_inputLength ];
// If adding new factors here, add them to
// getHighestSupportedFactor in the header as well
if(m_decFactor == 8)
{
//////////////////////////////////////////////////
b[0] = 0.060111378492136;
b[1] = -0.257323420830598;
b[2] = 0.420583503165928;
b[3] = -0.222750785197418;
b[4] = -0.222750785197418;
b[5] = 0.420583503165928;
b[6] = -0.257323420830598;
b[7] = 0.060111378492136;
a[0] = 1;
a[1] = -5.667654878577432;
a[2] = 14.062452278088417;
a[3] = -19.737303840697738;
a[4] = 16.889698874608641;
a[5] = -8.796600612325928;
a[6] = 2.577553446979888;
a[7] = -0.326903916815751;
//////////////////////////////////////////////////
}
else if( m_decFactor == 4 )
{
//////////////////////////////////////////////////
b[ 0 ] = 0.10133306904918619;
b[ 1 ] = -0.2447523353702363;
b[ 2 ] = 0.33622528590120965;
b[ 3 ] = -0.13936581560633518;
b[ 4 ] = -0.13936581560633382;
b[ 5 ] = 0.3362252859012087;
b[ 6 ] = -0.2447523353702358;
b[ 7 ] = 0.10133306904918594;
a[ 0 ] = 1;
a[ 1 ] = -3.9035590278139427;
a[ 2 ] = 7.5299379980621133;
a[ 3 ] = -8.6890803793177511;
a[ 4 ] = 6.4578667096099176;
a[ 5 ] = -3.0242979431223631;
a[ 6 ] = 0.83043385136748382;
a[ 7 ] = -0.094420800837809335;
//////////////////////////////////////////////////
}
else if( m_decFactor == 2 )
{
//////////////////////////////////////////////////
b[ 0 ] = 0.20898944260075727;
b[ 1 ] = 0.40011234879814367;
b[ 2 ] = 0.819741973072733;
b[ 3 ] = 1.0087419911682323;
b[ 4 ] = 1.0087419911682325;
b[ 5 ] = 0.81974197307273156;
b[ 6 ] = 0.40011234879814295;
b[ 7 ] = 0.20898944260075661;
a[ 0 ] = 1;
a[ 1 ] = 0.0077331184208358217;
a[ 2 ] = 1.9853971155964376;
a[ 3 ] = 0.19296739275341004;
a[ 4 ] = 1.2330748872852182;
a[ 5 ] = 0.18705341389316466;
a[ 6 ] = 0.23659265908013868;
a[ 7 ] = 0.032352924250533946;
}
else
{
if ( m_decFactor != 1 ) {
std::cerr << "WARNING: Decimator::initialise: unsupported decimation factor " << m_decFactor << ", no antialiasing filter will be used" << std::endl;
}
//////////////////////////////////////////////////
b[ 0 ] = 1;
b[ 1 ] = 0;
b[ 2 ] = 0;
b[ 3 ] = 0;
b[ 4 ] = 0;
b[ 5 ] = 0;
b[ 6 ] = 0;
b[ 7 ] = 0;
a[ 0 ] = 1;
a[ 1 ] = 0;
a[ 2 ] = 0;
a[ 3 ] = 0;
a[ 4 ] = 0;
a[ 5 ] = 0;
a[ 6 ] = 0;
a[ 7 ] = 0;
}
resetFilter();
}
void Decimator::deInitialise()
{
delete [] decBuffer;
}
void Decimator::resetFilter()
{
Input = Output = 0;
o1=o2=o3=o4=o5=o6=o7=0;
}
void Decimator::doAntiAlias(const double *src, double *dst, unsigned int length)
{
for( unsigned int i = 0; i < length; i++ )
{
Input = (double)src[ i ];
Output = Input * b[ 0 ] + o1;
o1 = Input * b[ 1 ] - Output * a[ 1 ] + o2;
o2 = Input * b[ 2 ] - Output * a[ 2 ] + o3;
o3 = Input * b[ 3 ] - Output * a[ 3 ] + o4;
o4 = Input * b[ 4 ] - Output * a[ 4 ] + o5;
o5 = Input * b[ 5 ] - Output * a[ 5 ] + o6;
o6 = Input * b[ 6 ] - Output * a[ 6 ] + o7;
o7 = Input * b[ 7 ] - Output * a[ 7 ] ;
dst[ i ] = Output;
}
}
void Decimator::doAntiAlias(const float *src, double *dst, unsigned int length)
{
for( unsigned int i = 0; i < length; i++ )
{
Input = (double)src[ i ];
Output = Input * b[ 0 ] + o1;
o1 = Input * b[ 1 ] - Output * a[ 1 ] + o2;
o2 = Input * b[ 2 ] - Output * a[ 2 ] + o3;
o3 = Input * b[ 3 ] - Output * a[ 3 ] + o4;
o4 = Input * b[ 4 ] - Output * a[ 4 ] + o5;
o5 = Input * b[ 5 ] - Output * a[ 5 ] + o6;
o6 = Input * b[ 6 ] - Output * a[ 6 ] + o7;
o7 = Input * b[ 7 ] - Output * a[ 7 ] ;
dst[ i ] = Output;
}
}
void Decimator::process(const double *src, double *dst)
{
if( m_decFactor != 1 )
{
doAntiAlias( src, decBuffer, m_inputLength );
}
unsigned idx = 0;
for( unsigned int i = 0; i < m_outputLength; i++ )
{
dst[ idx++ ] = decBuffer[ m_decFactor * i ];
}
}
void Decimator::process(const float *src, float *dst)
{
if( m_decFactor != 1 )
{
doAntiAlias( src, decBuffer, m_inputLength );
}
unsigned idx = 0;
for( unsigned int i = 0; i < m_outputLength; i++ )
{
dst[ idx++ ] = decBuffer[ m_decFactor * i ];
}
}

View File

@ -0,0 +1,62 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 DECIMATOR_H
#define DECIMATOR_H
class Decimator
{
public:
void process( const double* src, double* dst );
void process( const float* src, float* dst );
/**
* Construct a Decimator to operate on input blocks of length
* inLength, with decimation factor decFactor. inLength should be
* a multiple of decFactor. Output blocks will be of length
* inLength / decFactor.
*
* decFactor must be a power of two. The highest supported factor
* is obtained through getHighestSupportedFactor(); for higher
* factors, you will need to chain more than one decimator.
*/
Decimator( unsigned int inLength, unsigned int decFactor );
virtual ~Decimator();
int getFactor() const { return m_decFactor; }
static int getHighestSupportedFactor() { return 8; }
private:
void resetFilter();
void deInitialise();
void initialise( unsigned int inLength, unsigned int decFactor );
void doAntiAlias( const double* src, double* dst, unsigned int length );
void doAntiAlias( const float* src, double* dst, unsigned int length );
unsigned int m_inputLength;
unsigned int m_outputLength;
unsigned int m_decFactor;
double Input;
double Output ;
double o1,o2,o3,o4,o5,o6,o7;
double a[ 9 ];
double b[ 9 ];
double* decBuffer;
};
#endif //

View File

@ -0,0 +1,60 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2008 Kurt Jacobson and QMUL.
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 "BeatSpectrum.h"
#include "maths/CosineDistance.h"
using std::vector;
vector<double> BeatSpectrum::process(const vector<vector<double> > &m)
{
int origin = 0;
int sz = m.size()/2;
int i, j, k;
vector<double> v(sz);
for (i = 0; i < sz; ++i) v[i] = 0.0;
CosineDistance cd;
for (i = origin; i < origin + sz; ++i) {
k = 0;
for (j = i + 1; j < i + sz + 1; ++j) {
v[k++] += cd.distance(m[i], m[j]);
}
}
// normalize
double max = 0.0;
for (i = 0; i < sz; ++i) {
if (v[i] > max) max = v[i];
}
if (max > 0.0) {
for (i = 0; i < sz; ++i) {
v[i] /= max;
}
}
return v;
}

View File

@ -0,0 +1,40 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2008 Kurt Jacobson and QMUL.
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 BEATSPECTRUM_H
#define BEATSPECTRUM_H
#include <vector>
/**
* Given a matrix of "feature values", calculate a self-similarity
* vector. The resulting vector will have half as many elements as
* the number of columns in the matrix. This is based on the
* SoundBite rhythmic similarity code.
*/
class BeatSpectrum
{
public:
BeatSpectrum() { }
~BeatSpectrum() { }
std::vector<double> process(const std::vector<std::vector<double> > &inmatrix);
};
#endif

View File

@ -0,0 +1,398 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
* ClusterMeltSegmenter.cpp
*
* Created by Mark Levy on 23/03/2006.
* Copyright 2006 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 <cfloat>
#include <cmath>
#include "ClusterMeltSegmenter.h"
#include "cluster_segmenter.h"
#include "segment.h"
#include "dsp/transforms/FFT.h"
#include "dsp/chromagram/ConstantQ.h"
#include "dsp/rateconversion/Decimator.h"
#include "dsp/mfcc/MFCC.h"
ClusterMeltSegmenter::ClusterMeltSegmenter(ClusterMeltSegmenterParams params) :
window(NULL),
fft(NULL),
constq(NULL),
mfcc(NULL),
featureType(params.featureType),
hopSize(params.hopSize),
windowSize(params.windowSize),
fmin(params.fmin),
fmax(params.fmax),
nbins(params.nbins),
ncomponents(params.ncomponents), // NB currently not passed - no. of PCA components is set in cluser_segmenter.c
nHMMStates(params.nHMMStates),
nclusters(params.nclusters),
histogramLength(params.histogramLength),
neighbourhoodLimit(params.neighbourhoodLimit),
decimator(NULL)
{
}
void ClusterMeltSegmenter::initialise(int fs)
{
samplerate = fs;
if (featureType == FEATURE_TYPE_CONSTQ ||
featureType == FEATURE_TYPE_CHROMA) {
// run internal processing at 11025 or thereabouts
int internalRate = 11025;
int decimationFactor = samplerate / internalRate;
if (decimationFactor < 1) decimationFactor = 1;
// must be a power of two
while (decimationFactor & (decimationFactor - 1)) ++decimationFactor;
if (decimationFactor > Decimator::getHighestSupportedFactor()) {
decimationFactor = Decimator::getHighestSupportedFactor();
}
if (decimationFactor > 1) {
decimator = new Decimator(getWindowsize(), decimationFactor);
}
CQConfig config;
config.FS = samplerate / decimationFactor;
config.min = fmin;
config.max = fmax;
config.BPO = nbins;
config.CQThresh = 0.0054;
constq = new ConstantQ(config);
constq->sparsekernel();
ncoeff = constq->getK();
fft = new FFTReal(constq->getfftlength());
} else if (featureType == FEATURE_TYPE_MFCC) {
// run internal processing at 22050 or thereabouts
int internalRate = 22050;
int decimationFactor = samplerate / internalRate;
if (decimationFactor < 1) decimationFactor = 1;
// must be a power of two
while (decimationFactor & (decimationFactor - 1)) ++decimationFactor;
if (decimationFactor > Decimator::getHighestSupportedFactor()) {
decimationFactor = Decimator::getHighestSupportedFactor();
}
if (decimationFactor > 1) {
decimator = new Decimator(getWindowsize(), decimationFactor);
}
MFCCConfig config(samplerate / decimationFactor);
config.fftsize = 2048;
config.nceps = 19;
config.want_c0 = true;
mfcc = new MFCC(config);
ncoeff = config.nceps + 1;
}
}
ClusterMeltSegmenter::~ClusterMeltSegmenter()
{
delete window;
delete constq;
delete decimator;
delete fft;
}
int
ClusterMeltSegmenter::getWindowsize()
{
return static_cast<int>(windowSize * samplerate + 0.001);
}
int
ClusterMeltSegmenter::getHopsize()
{
return static_cast<int>(hopSize * samplerate + 0.001);
}
void ClusterMeltSegmenter::extractFeatures(const double* samples, int nsamples)
{
if (featureType == FEATURE_TYPE_CONSTQ ||
featureType == FEATURE_TYPE_CHROMA) {
extractFeaturesConstQ(samples, nsamples);
} else if (featureType == FEATURE_TYPE_MFCC) {
extractFeaturesMFCC(samples, nsamples);
}
}
void ClusterMeltSegmenter::extractFeaturesConstQ(const double* samples, int nsamples)
{
if (!constq) {
std::cerr << "ERROR: ClusterMeltSegmenter::extractFeaturesConstQ: "
<< "No const-q: initialise not called?"
<< std::endl;
return;
}
if (nsamples < getWindowsize()) {
std::cerr << "ERROR: ClusterMeltSegmenter::extractFeatures: nsamples < windowsize (" << nsamples << " < " << getWindowsize() << ")" << std::endl;
return;
}
int fftsize = constq->getfftlength();
if (!window || window->getSize() != fftsize) {
delete window;
window = new Window<double>(HammingWindow, fftsize);
}
vector<double> cq(ncoeff);
for (int i = 0; i < ncoeff; ++i) cq[i] = 0.0;
const double *psource = samples;
int pcount = nsamples;
if (decimator) {
pcount = nsamples / decimator->getFactor();
double *decout = new double[pcount];
decimator->process(samples, decout);
psource = decout;
}
int origin = 0;
// std::cerr << "nsamples = " << nsamples << ", pcount = " << pcount << std::endl;
int frames = 0;
double *frame = new double[fftsize];
double *real = new double[fftsize];
double *imag = new double[fftsize];
double *cqre = new double[ncoeff];
double *cqim = new double[ncoeff];
while (origin <= pcount) {
// always need at least one fft window per block, but after
// that we want to avoid having any incomplete ones
if (origin > 0 && origin + fftsize >= pcount) break;
for (int i = 0; i < fftsize; ++i) {
if (origin + i < pcount) {
frame[i] = psource[origin + i];
} else {
frame[i] = 0.0;
}
}
for (int i = 0; i < fftsize/2; ++i) {
double value = frame[i];
frame[i] = frame[i + fftsize/2];
frame[i + fftsize/2] = value;
}
window->cut(frame);
fft->process(false, frame, real, imag);
constq->process(real, imag, cqre, cqim);
for (int i = 0; i < ncoeff; ++i) {
cq[i] += sqrt(cqre[i] * cqre[i] + cqim[i] * cqim[i]);
}
++frames;
origin += fftsize/2;
}
delete [] cqre;
delete [] cqim;
delete [] real;
delete [] imag;
delete [] frame;
for (int i = 0; i < ncoeff; ++i) {
cq[i] /= frames;
}
if (decimator) delete[] psource;
features.push_back(cq);
}
void ClusterMeltSegmenter::extractFeaturesMFCC(const double* samples, int nsamples)
{
if (!mfcc) {
std::cerr << "ERROR: ClusterMeltSegmenter::extractFeaturesMFCC: "
<< "No mfcc: initialise not called?"
<< std::endl;
return;
}
if (nsamples < getWindowsize()) {
std::cerr << "ERROR: ClusterMeltSegmenter::extractFeatures: nsamples < windowsize (" << nsamples << " < " << getWindowsize() << ")" << std::endl;
return;
}
int fftsize = mfcc->getfftlength();
vector<double> cc(ncoeff);
for (int i = 0; i < ncoeff; ++i) cc[i] = 0.0;
const double *psource = samples;
int pcount = nsamples;
if (decimator) {
pcount = nsamples / decimator->getFactor();
double *decout = new double[pcount];
decimator->process(samples, decout);
psource = decout;
}
int origin = 0;
int frames = 0;
double *frame = new double[fftsize];
double *ccout = new double[ncoeff];
while (origin <= pcount) {
// always need at least one fft window per block, but after
// that we want to avoid having any incomplete ones
if (origin > 0 && origin + fftsize >= pcount) break;
for (int i = 0; i < fftsize; ++i) {
if (origin + i < pcount) {
frame[i] = psource[origin + i];
} else {
frame[i] = 0.0;
}
}
mfcc->process(frame, ccout);
for (int i = 0; i < ncoeff; ++i) {
cc[i] += ccout[i];
}
++frames;
origin += fftsize/2;
}
delete [] ccout;
delete [] frame;
for (int i = 0; i < ncoeff; ++i) {
cc[i] /= frames;
}
if (decimator) delete[] psource;
features.push_back(cc);
}
void ClusterMeltSegmenter::segment(int m)
{
nclusters = m;
segment();
}
void ClusterMeltSegmenter::setFeatures(const vector<vector<double> >& f)
{
features = f;
featureType = FEATURE_TYPE_UNKNOWN;
}
void ClusterMeltSegmenter::segment()
{
delete constq;
constq = 0;
delete mfcc;
mfcc = 0;
delete decimator;
decimator = 0;
if (features.size() < histogramLength) return;
/*
std::cerr << "ClusterMeltSegmenter::segment: have " << features.size()
<< " features with " << features[0].size() << " coefficients (ncoeff = " << ncoeff << ", ncomponents = " << ncomponents << ")" << std::endl;
*/
// copy the features to a native array and use the existing C segmenter...
double** arrFeatures = new double*[features.size()];
for (int i = 0; i < features.size(); i++)
{
if (featureType == FEATURE_TYPE_UNKNOWN) {
arrFeatures[i] = new double[features[0].size()];
for (int j = 0; j < features[0].size(); j++)
arrFeatures[i][j] = features[i][j];
} else {
arrFeatures[i] = new double[ncoeff+1]; // allow space for the normalised envelope
for (int j = 0; j < ncoeff; j++)
arrFeatures[i][j] = features[i][j];
}
}
q = new int[features.size()];
if (featureType == FEATURE_TYPE_UNKNOWN ||
featureType == FEATURE_TYPE_MFCC)
cluster_segment(q, arrFeatures, features.size(), features[0].size(), nHMMStates, histogramLength,
nclusters, neighbourhoodLimit);
else
constq_segment(q, arrFeatures, features.size(), nbins, ncoeff, featureType,
nHMMStates, histogramLength, nclusters, neighbourhoodLimit);
// convert the cluster assignment sequence to a segmentation
makeSegmentation(q, features.size());
// de-allocate arrays
delete [] q;
for (int i = 0; i < features.size(); i++)
delete [] arrFeatures[i];
delete [] arrFeatures;
// clear the features
clear();
}
void ClusterMeltSegmenter::makeSegmentation(int* q, int len)
{
segmentation.segments.clear();
segmentation.nsegtypes = nclusters;
segmentation.samplerate = samplerate;
Segment segment;
segment.start = 0;
segment.type = q[0];
for (int i = 1; i < len; i++)
{
if (q[i] != q[i-1])
{
segment.end = i * getHopsize();
segmentation.segments.push_back(segment);
segment.type = q[i];
segment.start = segment.end;
}
}
segment.end = len * getHopsize();
segmentation.segments.push_back(segment);
}

View File

@ -0,0 +1,109 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
* ClusterMeltSegmenter.h
*
* Created by Mark Levy on 23/03/2006.
* Copyright 2006 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 <vector>
#include "segment.h"
#include "Segmenter.h"
#include "hmm/hmm.h"
#include "base/Window.h"
using std::vector;
class Decimator;
class ConstantQ;
class MFCC;
class FFTReal;
class ClusterMeltSegmenterParams
// defaults are sensible for 11025Hz with 0.2 second hopsize
{
public:
ClusterMeltSegmenterParams() :
featureType(FEATURE_TYPE_CONSTQ),
hopSize(0.2),
windowSize(0.6),
fmin(62),
fmax(16000),
nbins(8),
ncomponents(20),
nHMMStates(40),
nclusters(10),
histogramLength(15),
neighbourhoodLimit(20) { }
feature_types featureType;
double hopSize; // in secs
double windowSize; // in secs
int fmin;
int fmax;
int nbins;
int ncomponents;
int nHMMStates;
int nclusters;
int histogramLength;
int neighbourhoodLimit;
};
class ClusterMeltSegmenter : public Segmenter
{
public:
ClusterMeltSegmenter(ClusterMeltSegmenterParams params);
virtual ~ClusterMeltSegmenter();
virtual void initialise(int samplerate);
virtual int getWindowsize();
virtual int getHopsize();
virtual void extractFeatures(const double* samples, int nsamples);
void setFeatures(const vector<vector<double> >& f); // provide the features yourself
virtual void segment(); // segment into default number of segment-types
void segment(int m); // segment into m segment-types
int getNSegmentTypes() { return nclusters; }
protected:
void makeSegmentation(int* q, int len);
void extractFeaturesConstQ(const double *, int);
void extractFeaturesMFCC(const double *, int);
Window<double> *window;
FFTReal *fft;
ConstantQ* constq;
MFCC* mfcc;
model_t* model; // the HMM
int* q; // the decoded HMM state sequence
vector<vector<double> > histograms;
feature_types featureType;
double hopSize; // in seconds
double windowSize; // in seconds
// constant-Q parameters
int fmin;
int fmax;
int nbins;
int ncoeff;
// PCA parameters
int ncomponents;
// HMM parameters
int nHMMStates;
// clustering parameters
int nclusters;
int histogramLength;
int neighbourhoodLimit;
Decimator *decimator;
};

View File

@ -0,0 +1,31 @@
/*
* Segmenter.cpp
*
* Created by Mark Levy on 04/04/2006.
* Copyright 2006 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 <iomanip>
#include "Segmenter.h"
ostream& operator<<(ostream& os, const Segmentation& s)
{
os << "structure_name : begin_time end_time\n";
for (int i = 0; i < s.segments.size(); i++)
{
Segment seg = s.segments[i];
os << std::fixed << seg.type << ':' << '\t' << std::setprecision(6) << seg.start / static_cast<double>(s.samplerate)
<< '\t' << std::setprecision(6) << seg.end / static_cast<double>(s.samplerate) << "\n";
}
return os;
}

View File

@ -0,0 +1,62 @@
#ifndef _SEGMENTER_H
#define _SEGMENTER_H
/*
* Segmenter.h
* soundbite
*
* Created by Mark Levy on 23/03/2006.
* Copyright 2006 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 <vector>
#include <iostream>
using std::vector;
using std::ostream;
class Segment
{
public:
int start; // in samples
int end;
int type;
};
class Segmentation
{
public:
int nsegtypes; // number of segment types, so possible types are {0,1,...,nsegtypes-1}
int samplerate;
vector<Segment> segments;
};
ostream& operator<<(ostream& os, const Segmentation& s);
class Segmenter
{
public:
Segmenter() {}
virtual ~Segmenter() {}
virtual void initialise(int samplerate) = 0; // must be called before any other methods
virtual int getWindowsize() = 0; // required window size for calls to extractFeatures()
virtual int getHopsize() = 0; // required hop size for calls to extractFeatures()
virtual void extractFeatures(const double* samples, int nsamples) = 0;
virtual void segment() = 0; // call once all the features have been extracted
virtual void segment(int m) = 0; // specify desired number of segment-types
virtual void clear() { features.clear(); }
const Segmentation& getSegmentation() const { return segmentation; }
protected:
vector<vector<double> > features;
Segmentation segmentation;
int samplerate;
};
#endif

View File

@ -0,0 +1,225 @@
/*
* cluster.c
* cluster_melt
*
* Created by Mark Levy on 21/02/2006.
* Copyright 2006 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 <stdlib.h>
#include "cluster_melt.h"
#define DEFAULT_LAMBDA 0.02;
#define DEFAULT_LIMIT 20;
double kldist(double* a, double* b, int n) {
/* NB assume that all a[i], b[i] are non-negative
because a, b represent probability distributions */
double q, d;
int i;
d = 0;
for (i = 0; i < n; i++)
{
q = (a[i] + b[i]) / 2.0;
if (q > 0)
{
if (a[i] > 0)
d += a[i] * log(a[i] / q);
if (b[i] > 0)
d += b[i] * log(b[i] / q);
}
}
return d;
}
void cluster_melt(double *h, int m, int n, double *Bsched, int t, int k, int l, int *c) {
double lambda, sum, beta, logsumexp, maxlp;
int i, j, a, b, b0, b1, limit, B, it, maxiter, maxiter0, maxiter1;
double** cl; /* reference histograms for each cluster */
int** nc; /* neighbour counts for each histogram */
double** lp; /* soft assignment probs for each histogram */
int* oldc; /* previous hard assignments (to check convergence) */
/* NB h is passed as a 1d row major array */
/* parameter values */
lambda = DEFAULT_LAMBDA;
if (l > 0)
limit = l;
else
limit = DEFAULT_LIMIT; /* use default if no valid neighbourhood limit supplied */
B = 2 * limit + 1;
maxiter0 = 20; /* number of iterations at initial temperature */
maxiter1 = 5; /* number of iterations at subsequent temperatures */
/* allocate memory */
cl = (double**) malloc(k*sizeof(double*));
for (i= 0; i < k; i++)
cl[i] = (double*) malloc(m*sizeof(double));
nc = (int**) malloc(n*sizeof(int*));
for (i= 0; i < n; i++)
nc[i] = (int*) malloc(k*sizeof(int));
lp = (double**) malloc(n*sizeof(double*));
for (i= 0; i < n; i++)
lp[i] = (double*) malloc(k*sizeof(double));
oldc = (int*) malloc(n * sizeof(int));
/* initialise */
for (i = 0; i < k; i++)
{
sum = 0;
for (j = 0; j < m; j++)
{
cl[i][j] = rand(); /* random initial reference histograms */
sum += cl[i][j] * cl[i][j];
}
sum = sqrt(sum);
for (j = 0; j < m; j++)
{
cl[i][j] /= sum; /* normalise */
}
}
//print_array(cl, k, m);
for (i = 0; i < n; i++)
c[i] = 1; /* initially assign all histograms to cluster 1 */
for (a = 0; a < t; a++)
{
beta = Bsched[a];
if (a == 0)
maxiter = maxiter0;
else
maxiter = maxiter1;
for (it = 0; it < maxiter; it++)
{
//if (it == maxiter - 1)
// mexPrintf("hasn't converged after %d iterations\n", maxiter);
for (i = 0; i < n; i++)
{
/* save current hard assignments */
oldc[i] = c[i];
/* calculate soft assignment logprobs for each cluster */
sum = 0;
for (j = 0; j < k; j++)
{
lp[i][ j] = -beta * kldist(cl[j], &h[i*m], m);
/* update matching neighbour counts for this histogram, based on current hard assignments */
/* old version:
nc[i][j] = 0;
if (i >= limit && i <= n - 1 - limit)
{
for (b = i - limit; b <= i + limit; b++)
{
if (c[b] == j+1)
nc[i][j]++;
}
nc[i][j] = B - nc[i][j];
}
*/
b0 = i - limit;
if (b0 < 0)
b0 = 0;
b1 = i + limit;
if (b1 >= n)
b1 = n - 1;
nc[i][j] = b1 - b0 + 1; /* = B except at edges */
for (b = b0; b <= b1; b++)
if (c[b] == j+1)
nc[i][j]--;
sum += exp(lp[i][j]);
}
/* normalise responsibilities and add duration logprior */
logsumexp = log(sum);
for (j = 0; j < k; j++)
lp[i][j] -= logsumexp + lambda * nc[i][j];
}
//print_array(lp, n, k);
/*
for (i = 0; i < n; i++)
{
for (j = 0; j < k; j++)
mexPrintf("%d ", nc[i][j]);
mexPrintf("\n");
}
*/
/* update the assignments now that we know the duration priors
based on the current assignments */
for (i = 0; i < n; i++)
{
maxlp = lp[i][0];
c[i] = 1;
for (j = 1; j < k; j++)
if (lp[i][j] > maxlp)
{
maxlp = lp[i][j];
c[i] = j+1;
}
}
/* break if assignments haven't changed */
i = 0;
while (i < n && oldc[i] == c[i])
i++;
if (i == n)
break;
/* update reference histograms now we know new responsibilities */
for (j = 0; j < k; j++)
{
for (b = 0; b < m; b++)
{
cl[j][b] = 0;
for (i = 0; i < n; i++)
{
cl[j][b] += exp(lp[i][j]) * h[i*m+b];
}
}
sum = 0;
for (i = 0; i < n; i++)
sum += exp(lp[i][j]);
for (b = 0; b < m; b++)
cl[j][b] /= sum; /* normalise */
}
//print_array(cl, k, m);
//mexPrintf("\n\n");
}
}
/* free memory */
for (i = 0; i < k; i++)
free(cl[i]);
free(cl);
for (i = 0; i < n; i++)
free(nc[i]);
free(nc);
for (i = 0; i < n; i++)
free(lp[i]);
free(lp);
free(oldc);
}

View File

@ -0,0 +1,39 @@
#ifndef _CLUSTER_MELT_H
#define _CLUSTER_MELT_H
/*
* cluster_melt.h
* cluster_melt
*
* Created by Mark Levy on 21/02/2006.
* Copyright 2006 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 <stdlib.h>
#include <math.h>
#ifdef __cplusplus
extern "C" {
#endif
void cluster_melt(double *h, /* normalised histograms, as a vector in row major order */
int m, /* number of dimensions (i.e. histogram bins) */
int n, /* number of histograms */
double *Bsched, /* inverse temperature schedule */
int t, /* length of schedule */
int k, /* number of clusters */
int l, /* neighbourhood limit (supply zero to use default value) */
int *c /* sequence of cluster assignments */
);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,285 @@
/*
* cluster_segmenter.c
* soundbite
*
* Created by Mark Levy on 06/04/2006.
* Copyright 2006 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 "cluster_segmenter.h"
extern int readmatarray_size(const char *filepath, int n_array, int* t, int* d);
extern int readmatarray(const char *filepath, int n_array, int t, int d, double** arr);
/* converts constant-Q features to normalised chroma */
void cq2chroma(double** cq, int nframes, int ncoeff, int bins, double** chroma)
{
int noct = ncoeff / bins; /* number of complete octaves in constant-Q */
int t, b, oct, ix;
//double maxchroma; /* max chroma value at each time, for normalisation */
//double sum; /* for normalisation */
for (t = 0; t < nframes; t++)
{
for (b = 0; b < bins; b++)
chroma[t][b] = 0;
for (oct = 0; oct < noct; oct++)
{
ix = oct * bins;
for (b = 0; b < bins; b++)
chroma[t][b] += fabs(cq[t][ix+b]);
}
/* normalise to unit sum
sum = 0;
for (b = 0; b < bins; b++)
sum += chroma[t][b];
for (b = 0; b < bins; b++)
chroma[t][b] /= sum;
*/
/* normalise to unit max - NO this made results much worse!
maxchroma = 0;
for (b = 0; b < bins; b++)
if (chroma[t][b] > maxchroma)
maxchroma = chroma[t][b];
if (maxchroma > 0)
for (b = 0; b < bins; b++)
chroma[t][b] /= maxchroma;
*/
}
}
/* applies MPEG-7 normalisation to constant-Q features, storing normalised envelope (norm) in last feature dimension */
void mpeg7_constq(double** features, int nframes, int ncoeff)
{
int i, j;
double ss;
double env;
double maxenv = 0;
/* convert const-Q features to dB scale */
for (i = 0; i < nframes; i++)
for (j = 0; j < ncoeff; j++)
features[i][j] = 10.0 * log10(features[i][j]+DBL_EPSILON);
/* normalise each feature vector and add the norm as an extra feature dimension */
for (i = 0; i < nframes; i++)
{
ss = 0;
for (j = 0; j < ncoeff; j++)
ss += features[i][j] * features[i][j];
env = sqrt(ss);
for (j = 0; j < ncoeff; j++)
features[i][j] /= env;
features[i][ncoeff] = env;
if (env > maxenv)
maxenv = env;
}
/* normalise the envelopes */
for (i = 0; i < nframes; i++)
features[i][ncoeff] /= maxenv;
}
/* return histograms h[nx*m] of data x[nx] into m bins using a sliding window of length h_len (MUST BE ODD) */
/* NB h is a vector in row major order, as required by cluster_melt() */
/* for historical reasons we normalise the histograms by their norm (not to sum to one) */
void create_histograms(int* x, int nx, int m, int hlen, double* h)
{
int i, j, t;
double norm;
for (i = 0; i < nx*m; i++)
h[i] = 0;
for (i = hlen/2; i < nx-hlen/2; i++)
{
for (j = 0; j < m; j++)
h[i*m+j] = 0;
for (t = i-hlen/2; t <= i+hlen/2; t++)
++h[i*m+x[t]];
norm = 0;
for (j = 0; j < m; j++)
norm += h[i*m+j] * h[i*m+j];
for (j = 0; j < m; j++)
h[i*m+j] /= norm;
}
/* duplicate histograms at beginning and end to create one histogram for each data value supplied */
for (i = 0; i < hlen/2; i++)
for (j = 0; j < m; j++)
h[i*m+j] = h[hlen/2*m+j];
for (i = nx-hlen/2; i < nx; i++)
for (j = 0; j < m; j++)
h[i*m+j] = h[(nx-hlen/2-1)*m+j];
}
/* segment using HMM and then histogram clustering */
void cluster_segment(int* q, double** features, int frames_read, int feature_length, int nHMM_states,
int histogram_length, int nclusters, int neighbour_limit)
{
int i, j;
/*****************************/
if (0) {
/* try just using the predominant bin number as a 'decoded state' */
nHMM_states = feature_length + 1; /* allow a 'zero' state */
double chroma_thresh = 0.05;
double maxval;
int maxbin;
for (i = 0; i < frames_read; i++)
{
maxval = 0;
for (j = 0; j < feature_length; j++)
{
if (features[i][j] > maxval)
{
maxval = features[i][j];
maxbin = j;
}
}
if (maxval > chroma_thresh)
q[i] = maxbin;
else
q[i] = feature_length;
}
}
if (1) {
/*****************************/
/* scale all the features to 'balance covariances' during HMM training */
double scale = 10;
for (i = 0; i < frames_read; i++)
for (j = 0; j < feature_length; j++)
features[i][j] *= scale;
/* train an HMM on the features */
/* create a model */
model_t* model = hmm_init(features, frames_read, feature_length, nHMM_states);
/* train the model */
hmm_train(features, frames_read, model);
/*
printf("\n\nafter training:\n");
hmm_print(model);
*/
/* decode the hidden state sequence */
viterbi_decode(features, frames_read, model, q);
hmm_close(model);
/*****************************/
}
/*****************************/
/*
fprintf(stderr, "HMM state sequence:\n");
for (i = 0; i < frames_read; i++)
fprintf(stderr, "%d ", q[i]);
fprintf(stderr, "\n\n");
*/
/* create histograms of states */
double* h = (double*) malloc(frames_read*nHMM_states*sizeof(double)); /* vector in row major order */
create_histograms(q, frames_read, nHMM_states, histogram_length, h);
/* cluster the histograms */
int nbsched = 20; /* length of inverse temperature schedule */
double* bsched = (double*) malloc(nbsched*sizeof(double)); /* inverse temperature schedule */
double b0 = 100;
double alpha = 0.7;
bsched[0] = b0;
for (i = 1; i < nbsched; i++)
bsched[i] = alpha * bsched[i-1];
cluster_melt(h, nHMM_states, frames_read, bsched, nbsched, nclusters, neighbour_limit, q);
/* now q holds a sequence of cluster assignments */
free(h);
free(bsched);
}
/* segment constant-Q or chroma features */
void constq_segment(int* q, double** features, int frames_read, int bins, int ncoeff, int feature_type,
int nHMM_states, int histogram_length, int nclusters, int neighbour_limit)
{
int feature_length;
double** chroma;
int i;
if (feature_type == FEATURE_TYPE_CONSTQ)
{
/* fprintf(stderr, "Converting to dB and normalising...\n");
*/
mpeg7_constq(features, frames_read, ncoeff);
/*
fprintf(stderr, "Running PCA...\n");
*/
/* do PCA on the features (but not the envelope) */
int ncomponents = 20;
pca_project(features, frames_read, ncoeff, ncomponents);
/* copy the envelope so that it immediatly follows the chosen components */
for (i = 0; i < frames_read; i++)
features[i][ncomponents] = features[i][ncoeff];
feature_length = ncomponents + 1;
/**************************************
//TEST
// feature file name
char* dir = "/Users/mark/documents/semma/audio/";
char* file_name = (char*) malloc((strlen(dir) + strlen(trackname) + strlen("_features_c20r8h0.2f0.6.mat") + 1)*sizeof(char));
strcpy(file_name, dir);
strcat(file_name, trackname);
strcat(file_name, "_features_c20r8h0.2f0.6.mat");
// get the features from Matlab from mat-file
int frames_in_file;
readmatarray_size(file_name, 2, &frames_in_file, &feature_length);
readmatarray(file_name, 2, frames_in_file, feature_length, features);
// copy final frame to ensure that we get as many as we expected
int missing_frames = frames_read - frames_in_file;
while (missing_frames > 0)
{
for (i = 0; i < feature_length; i++)
features[frames_read-missing_frames][i] = features[frames_read-missing_frames-1][i];
--missing_frames;
}
free(file_name);
******************************************/
cluster_segment(q, features, frames_read, feature_length, nHMM_states, histogram_length, nclusters, neighbour_limit);
}
if (feature_type == FEATURE_TYPE_CHROMA)
{
/*
fprintf(stderr, "Converting to chroma features...\n");
*/
/* convert constant-Q to normalised chroma features */
chroma = (double**) malloc(frames_read*sizeof(double*));
for (i = 0; i < frames_read; i++)
chroma[i] = (double*) malloc(bins*sizeof(double));
cq2chroma(features, frames_read, ncoeff, bins, chroma);
feature_length = bins;
cluster_segment(q, chroma, frames_read, feature_length, nHMM_states, histogram_length, nclusters, neighbour_limit);
for (i = 0; i < frames_read; i++)
free(chroma[i]);
free(chroma);
}
}

View File

@ -0,0 +1,51 @@
#ifndef _CLUSTER_SEGMENTER_H
#define _CLUSTER_SEGMENTER_H
/*
* cluster_segmenter.h
* soundbite
*
* Created by Mark Levy on 06/04/2006.
* Copyright 2006 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 <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include "segment.h"
#include "cluster_melt.h"
#include "hmm/hmm.h"
#include "maths/pca/pca.h"
#ifdef __cplusplus
extern "C" {
#endif
/* applies MPEG-7 normalisation to constant-Q features, storing normalised envelope (norm) in last feature dimension */
void mpeg7_constq(double** features, int nframes, int ncoeff);
/* converts constant-Q features to normalised chroma */
void cq2chroma(double** cq, int nframes, int ncoeff, int bins, double** chroma);
void create_histograms(int* x, int nx, int m, int hlen, double* h);
void cluster_segment(int* q, double** features, int frames_read, int feature_length, int nHMM_states,
int histogram_length, int nclusters, int neighbour_limit);
void constq_segment(int* q, double** features, int frames_read, int bins, int ncoeff, int feature_type,
int nHMM_states, int histogram_length, int nclusters, int neighbour_limit);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,50 @@
#ifndef _SEGMENT_H
#define _SEGMENT_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* segment.h
*
* Created by Mark Levy on 06/04/2006.
* Copyright 2006 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.
*
*/
typedef struct segment_t
{
long start; /* in samples */
long end;
int type;
} segment_t;
typedef struct segmentation_t
{
int nsegs; /* number of segments */
int nsegtypes; /* number of segment types, so possible types are {0,1,...,nsegtypes-1} */
int samplerate;
segment_t* segments;
} segmentation_t;
typedef enum
{
FEATURE_TYPE_UNKNOWN = 0,
FEATURE_TYPE_CONSTQ = 1,
FEATURE_TYPE_CHROMA = 2,
FEATURE_TYPE_MFCC = 3
} feature_types;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,187 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 "DFProcess.h"
#include "maths/MathUtilities.h"
#include <cstring>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
DFProcess::DFProcess( DFProcConfig Config )
{
filtSrc = NULL;
filtDst = NULL;
m_filtScratchIn = NULL;
m_filtScratchOut = NULL;
m_FFOrd = 0;
initialise( Config );
}
DFProcess::~DFProcess()
{
deInitialise();
}
void DFProcess::initialise( DFProcConfig Config )
{
m_length = Config.length;
m_winPre = Config.winPre;
m_winPost = Config.winPost;
m_alphaNormParam = Config.AlphaNormParam;
m_isMedianPositive = Config.isMedianPositive;
filtSrc = new double[ m_length ];
filtDst = new double[ m_length ];
//Low Pass Smoothing Filter Config
m_FilterConfigParams.ord = Config.LPOrd;
m_FilterConfigParams.ACoeffs = Config.LPACoeffs;
m_FilterConfigParams.BCoeffs = Config.LPBCoeffs;
m_FiltFilt = new FiltFilt( m_FilterConfigParams );
}
void DFProcess::deInitialise()
{
delete [] filtSrc;
delete [] filtDst;
delete [] m_filtScratchIn;
delete [] m_filtScratchOut;
delete m_FiltFilt;
}
void DFProcess::process(double *src, double* dst)
{
if (m_length == 0) return;
removeDCNormalize( src, filtSrc );
m_FiltFilt->process( filtSrc, filtDst, m_length );
medianFilter( filtDst, dst );
}
void DFProcess::medianFilter(double *src, double *dst)
{
int i,k,j,l;
int index = 0;
double val = 0;
double* y = new double[ m_winPost + m_winPre + 1];
memset( y, 0, sizeof( double ) * ( m_winPost + m_winPre + 1) );
double* scratch = new double[ m_length ];
for( i = 0; i < m_winPre; i++)
{
if (index >= m_length) break;
k = i + m_winPost + 1;
for( j = 0; j < k; j++)
{
y[ j ] = src[ j ];
}
scratch[ index ] = MathUtilities::median( y, k );
index++;
}
for( i = 0; i + m_winPost + m_winPre < m_length; i ++)
{
if (index >= m_length) break;
l = 0;
for( j = i; j < ( i + m_winPost + m_winPre + 1); j++)
{
y[ l ] = src[ j ];
l++;
}
scratch[ index++ ] = MathUtilities::median( y, (m_winPost + m_winPre + 1 ));
}
for( i = std::max( m_length - m_winPost, 1); i < m_length; i++)
{
if (index >= m_length) break;
k = std::max( i - m_winPre, 1);
l = 0;
for( j = k; j < m_length; j++)
{
y[ l ] = src[ j ];
l++;
}
scratch[ index++ ] = MathUtilities::median( y, l);
}
for( i = 0; i < m_length; i++ )
{
val = src[ i ] - scratch[ i ];// - 0.033;
if( m_isMedianPositive )
{
if( val > 0 )
{
dst[ i ] = val;
}
else
{
dst[ i ] = 0;
}
}
else
{
dst[ i ] = val;
}
}
delete [] y;
delete [] scratch;
}
void DFProcess::removeDCNormalize( double *src, double*dst )
{
double DFmax = 0;
double DFMin = 0;
double DFAlphaNorm = 0;
MathUtilities::getFrameMinMax( src, m_length, &DFMin, &DFmax );
MathUtilities::getAlphaNorm( src, m_length, m_alphaNormParam, &DFAlphaNorm );
for( unsigned int i = 0; i< m_length; i++)
{
dst[ i ] = ( src[ i ] - DFMin ) / DFAlphaNorm;
}
}

View File

@ -0,0 +1,69 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 CDFPROCESS_H
#define CDFPROCESS_H
#include <stdio.h>
#include "FiltFilt.h"
struct DFProcConfig{
unsigned int length;
unsigned int LPOrd;
double *LPACoeffs;
double *LPBCoeffs;
unsigned int winPre;
unsigned int winPost;
double AlphaNormParam;
bool isMedianPositive;
};
class DFProcess
{
public:
DFProcess( DFProcConfig Config );
virtual ~DFProcess();
void process( double* src, double* dst );
private:
void initialise( DFProcConfig Config );
void deInitialise();
void removeDCNormalize( double *src, double*dst );
void medianFilter( double* src, double* dst );
int m_length;
int m_FFOrd;
int m_winPre;
int m_winPost;
double m_alphaNormParam;
double* filtSrc;
double* filtDst;
double* m_filtScratchIn;
double* m_filtScratchOut;
FiltFiltConfig m_FilterConfigParams;
FiltFilt* m_FiltFilt;
bool m_isMedianPositive;
};
#endif

View File

@ -0,0 +1,130 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 "FiltFilt.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
FiltFilt::FiltFilt( FiltFiltConfig Config )
{
m_filtScratchIn = NULL;
m_filtScratchOut = NULL;
m_ord = 0;
initialise( Config );
}
FiltFilt::~FiltFilt()
{
deInitialise();
}
void FiltFilt::initialise( FiltFiltConfig Config )
{
m_ord = Config.ord;
m_filterConfig.ord = Config.ord;
m_filterConfig.ACoeffs = Config.ACoeffs;
m_filterConfig.BCoeffs = Config.BCoeffs;
m_filter = new Filter( m_filterConfig );
}
void FiltFilt::deInitialise()
{
delete m_filter;
}
void FiltFilt::process(double *src, double *dst, unsigned int length)
{
unsigned int i;
if (length == 0) return;
unsigned int nFilt = m_ord + 1;
unsigned int nFact = 3 * ( nFilt - 1);
unsigned int nExt = length + 2 * nFact;
m_filtScratchIn = new double[ nExt ];
m_filtScratchOut = new double[ nExt ];
for( i = 0; i< nExt; i++ )
{
m_filtScratchIn[ i ] = 0.0;
m_filtScratchOut[ i ] = 0.0;
}
// Edge transients reflection
double sample0 = 2 * src[ 0 ];
double sampleN = 2 * src[ length - 1 ];
unsigned int index = 0;
for( i = nFact; i > 0; i-- )
{
m_filtScratchIn[ index++ ] = sample0 - src[ i ];
}
index = 0;
for( i = 0; i < nFact; i++ )
{
m_filtScratchIn[ (nExt - nFact) + index++ ] = sampleN - src[ (length - 2) - i ];
}
index = 0;
for( i = 0; i < length; i++ )
{
m_filtScratchIn[ i + nFact ] = src[ i ];
}
////////////////////////////////
// Do 0Ph filtering
m_filter->process( m_filtScratchIn, m_filtScratchOut, nExt);
// reverse the series for FILTFILT
for ( i = 0; i < nExt; i++)
{
m_filtScratchIn[ i ] = m_filtScratchOut[ nExt - i - 1];
}
// do FILTER again
m_filter->process( m_filtScratchIn, m_filtScratchOut, nExt);
// reverse the series back
for ( i = 0; i < nExt; i++)
{
m_filtScratchIn[ i ] = m_filtScratchOut[ nExt - i - 1 ];
}
for ( i = 0;i < nExt; i++)
{
m_filtScratchOut[ i ] = m_filtScratchIn[ i ];
}
index = 0;
for( i = 0; i < length; i++ )
{
dst[ index++ ] = m_filtScratchOut[ i + nFact ];
}
delete [] m_filtScratchIn;
delete [] m_filtScratchOut;
}
void FiltFilt::reset()
{
}

View File

@ -0,0 +1,50 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 FILTFILT_H
#define FILTFILT_H
#include "Filter.h"
struct FiltFiltConfig{
unsigned int ord;
double* ACoeffs;
double* BCoeffs;
};
class FiltFilt
{
public:
FiltFilt( FiltFiltConfig Config );
virtual ~FiltFilt();
void reset();
void process( double* src, double* dst, unsigned int length );
private:
void initialise( FiltFiltConfig Config );
void deInitialise();
unsigned int m_ord;
Filter* m_filter;
double* m_filtScratchIn;
double* m_filtScratchOut;
FilterConfig m_filterConfig;
};
#endif

View File

@ -0,0 +1,87 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 "Filter.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Filter::Filter( FilterConfig Config )
{
m_ord = 0;
m_outBuffer = NULL;
m_inBuffer = NULL;
initialise( Config );
}
Filter::~Filter()
{
deInitialise();
}
void Filter::initialise( FilterConfig Config )
{
m_ord = Config.ord;
m_ACoeffs = Config.ACoeffs;
m_BCoeffs = Config.BCoeffs;
m_inBuffer = new double[ m_ord + 1 ];
m_outBuffer = new double[ m_ord + 1 ];
reset();
}
void Filter::deInitialise()
{
delete[] m_inBuffer;
delete[] m_outBuffer;
}
void Filter::reset()
{
for( unsigned int i = 0; i < m_ord+1; i++ ){ m_inBuffer[ i ] = 0.0; }
for(unsigned int i = 0; i < m_ord+1; i++ ){ m_outBuffer[ i ] = 0.0; }
}
void Filter::process( double *src, double *dst, unsigned int length )
{
unsigned int SP,i,j;
double xin,xout;
for (SP=0;SP<length;SP++)
{
xin=src[SP];
/* move buffer */
for ( i = 0; i < m_ord; i++) {m_inBuffer[ m_ord - i ]=m_inBuffer[ m_ord - i - 1 ];}
m_inBuffer[0]=xin;
xout=0.0;
for (j=0;j< m_ord + 1; j++)
xout = xout + m_BCoeffs[ j ] * m_inBuffer[ j ];
for (j = 0; j < m_ord; j++)
xout= xout - m_ACoeffs[ j + 1 ] * m_outBuffer[ j ];
dst[ SP ] = xout;
for ( i = 0; i < m_ord - 1; i++ ) { m_outBuffer[ m_ord - i - 1 ] = m_outBuffer[ m_ord - i - 2 ];}
m_outBuffer[0]=xout;
} /* end of SP loop */
}

View File

@ -0,0 +1,53 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 FILTER_H
#define FILTER_H
#ifndef NULL
#define NULL 0
#endif
struct FilterConfig{
unsigned int ord;
double* ACoeffs;
double* BCoeffs;
};
class Filter
{
public:
Filter( FilterConfig Config );
virtual ~Filter();
void reset();
void process( double *src, double *dst, unsigned int length );
private:
void initialise( FilterConfig Config );
void deInitialise();
unsigned int m_ord;
double* m_inBuffer;
double* m_outBuffer;
double* m_ACoeffs;
double* m_BCoeffs;
};
#endif

View File

@ -0,0 +1,109 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 "Framer.h"
#include <math.h>
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Framer::Framer()
{
m_dataFrame = NULL;
m_strideFrame = NULL;
}
Framer::~Framer()
{
if( m_dataFrame != NULL )
delete [] m_dataFrame;
if( m_strideFrame != NULL )
delete [] m_strideFrame;
}
void Framer::configure( unsigned int frameLength, unsigned int hop )
{
m_frameLength = frameLength;
m_stepSize = hop;
resetCounters();
if( m_dataFrame != NULL )
{
delete [] m_dataFrame;
m_dataFrame = NULL;
}
m_dataFrame = new double[ m_frameLength ];
if( m_strideFrame != NULL )
{
delete [] m_strideFrame;
m_strideFrame = NULL;
}
m_strideFrame = new double[ m_stepSize ];
}
void Framer::getFrame(double *dst)
{
if( (m_ulSrcIndex + ( m_frameLength) ) < m_ulSampleLen )
{
for( unsigned int u = 0; u < m_frameLength; u++)
{
dst[ u ] = m_srcBuffer[ m_ulSrcIndex++ ];
}
m_ulSrcIndex -= ( m_frameLength - m_stepSize );
}
else
{
unsigned int rem = (m_ulSampleLen - m_ulSrcIndex );
unsigned int zero = m_frameLength - rem;
for( unsigned int u = 0; u < rem; u++ )
{
dst[ u ] = m_srcBuffer[ m_ulSrcIndex++ ];
}
for( unsigned int u = 0; u < zero; u++ )
{
dst[ rem + u ] = 0;
}
m_ulSrcIndex -= (( rem - m_stepSize ) );
}
m_framesRead++;
}
void Framer::resetCounters()
{
m_framesRead = 0;
m_ulSrcIndex = 0;
}
unsigned int Framer::getMaxNoFrames()
{
return m_maxFrames;
}
void Framer::setSource(double *src, unsigned int length)
{
m_srcBuffer = src;
m_ulSampleLen = length;
m_maxFrames = (unsigned int)ceil( (double)m_ulSampleLen/(double)m_stepSize ) ;
}

View File

@ -0,0 +1,52 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 FRAMER_H
#define FRAMER_H
//#include <io.h>
#include <fcntl.h>
#include <stdio.h>
class Framer
{
public:
void setSource( double* src, unsigned int length );
unsigned int getMaxNoFrames();
void getFrame( double* dst );
void configure( unsigned int frameLength, unsigned int hop );
Framer();
virtual ~Framer();
void resetCounters();
private:
unsigned long m_ulSampleLen; // DataLength (samples)
unsigned int m_framesRead; // Read Frames Index
double* m_srcBuffer;
double* m_dataFrame; // Analysis Frame Buffer
double* m_strideFrame; // Stride Frame Buffer
unsigned int m_frameLength; // Analysis Frame Length
unsigned int m_stepSize; // Analysis Frame Stride
unsigned int m_maxFrames;
unsigned long m_ulSrcIndex;
};
#endif

View File

@ -0,0 +1,308 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2008-2009 Matthew Davies and QMUL.
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 "DownBeat.h"
#include "maths/MathAliases.h"
#include "maths/MathUtilities.h"
#include "maths/KLDivergence.h"
#include "dsp/transforms/FFT.h"
#include <iostream>
#include <cstdlib>
DownBeat::DownBeat(float originalSampleRate,
size_t decimationFactor,
size_t dfIncrement) :
m_bpb(0),
m_rate(originalSampleRate),
m_factor(decimationFactor),
m_increment(dfIncrement),
m_decimator1(0),
m_decimator2(0),
m_buffer(0),
m_decbuf(0),
m_bufsiz(0),
m_buffill(0),
m_beatframesize(0),
m_beatframe(0)
{
// beat frame size is next power of two up from 1.3 seconds at the
// downsampled rate (happens to produce 4096 for 44100 or 48000 at
// 16x decimation, which is our expected normal situation)
m_beatframesize = MathUtilities::nextPowerOfTwo
(int((m_rate / decimationFactor) * 1.3));
// std::cerr << "rate = " << m_rate << ", bfs = " << m_beatframesize << std::endl;
m_beatframe = new double[m_beatframesize];
m_fftRealOut = new double[m_beatframesize];
m_fftImagOut = new double[m_beatframesize];
m_fft = new FFTReal(m_beatframesize);
}
DownBeat::~DownBeat()
{
delete m_decimator1;
delete m_decimator2;
if (m_buffer) free(m_buffer);
delete[] m_decbuf;
delete[] m_beatframe;
delete[] m_fftRealOut;
delete[] m_fftImagOut;
delete m_fft;
}
void
DownBeat::setBeatsPerBar(int bpb)
{
m_bpb = bpb;
}
void
DownBeat::makeDecimators()
{
// std::cerr << "m_factor = " << m_factor << std::endl;
if (m_factor < 2) return;
size_t highest = Decimator::getHighestSupportedFactor();
if (m_factor <= highest) {
m_decimator1 = new Decimator(m_increment, m_factor);
// std::cerr << "DownBeat: decimator 1 factor " << m_factor << ", size " << m_increment << std::endl;
return;
}
m_decimator1 = new Decimator(m_increment, highest);
// std::cerr << "DownBeat: decimator 1 factor " << highest << ", size " << m_increment << std::endl;
m_decimator2 = new Decimator(m_increment / highest, m_factor / highest);
// std::cerr << "DownBeat: decimator 2 factor " << m_factor / highest << ", size " << m_increment / highest << std::endl;
m_decbuf = new float[m_increment / highest];
}
void
DownBeat::pushAudioBlock(const float *audio)
{
if (m_buffill + (m_increment / m_factor) > m_bufsiz) {
if (m_bufsiz == 0) m_bufsiz = m_increment * 16;
else m_bufsiz = m_bufsiz * 2;
if (!m_buffer) {
m_buffer = (float *)malloc(m_bufsiz * sizeof(float));
} else {
// std::cerr << "DownBeat::pushAudioBlock: realloc m_buffer to " << m_bufsiz << std::endl;
m_buffer = (float *)realloc(m_buffer, m_bufsiz * sizeof(float));
}
}
if (!m_decimator1 && m_factor > 1) makeDecimators();
// float rmsin = 0, rmsout = 0;
// for (int i = 0; i < m_increment; ++i) {
// rmsin += audio[i] * audio[i];
// }
if (m_decimator2) {
m_decimator1->process(audio, m_decbuf);
m_decimator2->process(m_decbuf, m_buffer + m_buffill);
} else if (m_decimator1) {
m_decimator1->process(audio, m_buffer + m_buffill);
} else {
// just copy across (m_factor is presumably 1)
for (size_t i = 0; i < m_increment; ++i) {
(m_buffer + m_buffill)[i] = audio[i];
}
}
// for (int i = 0; i < m_increment / m_factor; ++i) {
// rmsout += m_buffer[m_buffill + i] * m_buffer[m_buffill + i];
// }
// std::cerr << "pushAudioBlock: rms in " << sqrt(rmsin) << ", out " << sqrt(rmsout) << std::endl;
m_buffill += m_increment / m_factor;
}
const float *
DownBeat::getBufferedAudio(size_t &length) const
{
length = m_buffill;
return m_buffer;
}
void
DownBeat::resetAudioBuffer()
{
if (m_buffer) free(m_buffer);
m_buffer = 0;
m_buffill = 0;
m_bufsiz = 0;
}
void
DownBeat::findDownBeats(const float *audio,
size_t audioLength,
const d_vec_t &beats,
i_vec_t &downbeats)
{
// FIND DOWNBEATS BY PARTITIONING THE INPUT AUDIO FILE INTO BEAT SEGMENTS
// WHERE THE AUDIO FRAMES ARE DOWNSAMPLED BY A FACTOR OF 16 (fs ~= 2700Hz)
// THEN TAKING THE JENSEN-SHANNON DIVERGENCE BETWEEN BEAT SYNCHRONOUS SPECTRAL FRAMES
// IMPLEMENTATION (MOSTLY) FOLLOWS:
// DAVIES AND PLUMBLEY "A SPECTRAL DIFFERENCE APPROACH TO EXTRACTING DOWNBEATS IN MUSICAL AUDIO"
// EUSIPCO 2006, FLORENCE, ITALY
d_vec_t newspec(m_beatframesize / 2); // magnitude spectrum of current beat
d_vec_t oldspec(m_beatframesize / 2); // magnitude spectrum of previous beat
m_beatsd.clear();
if (audioLength == 0) return;
for (size_t i = 0; i + 1 < beats.size(); ++i) {
// Copy the extents of the current beat from downsampled array
// into beat frame buffer
size_t beatstart = (beats[i] * m_increment) / m_factor;
size_t beatend = (beats[i+1] * m_increment) / m_factor;
if (beatend >= audioLength) beatend = audioLength - 1;
if (beatend < beatstart) beatend = beatstart;
size_t beatlen = beatend - beatstart;
// Also apply a Hanning window to the beat frame buffer, sized
// to the beat extents rather than the frame size. (Because
// the size varies, it's easier to do this by hand than use
// our Window abstraction.)
// std::cerr << "beatlen = " << beatlen << std::endl;
// float rms = 0;
for (size_t j = 0; j < beatlen && j < m_beatframesize; ++j) {
double mul = 0.5 * (1.0 - cos(TWO_PI * (double(j) / double(beatlen))));
m_beatframe[j] = audio[beatstart + j] * mul;
// rms += m_beatframe[j] * m_beatframe[j];
}
// rms = sqrt(rms);
// std::cerr << "beat " << i << ": audio rms " << rms << std::endl;
for (size_t j = beatlen; j < m_beatframesize; ++j) {
m_beatframe[j] = 0.0;
}
// Now FFT beat frame
m_fft->process(false, m_beatframe, m_fftRealOut, m_fftImagOut);
// Calculate magnitudes
for (size_t j = 0; j < m_beatframesize/2; ++j) {
newspec[j] = sqrt(m_fftRealOut[j] * m_fftRealOut[j] +
m_fftImagOut[j] * m_fftImagOut[j]);
}
// Preserve peaks by applying adaptive threshold
MathUtilities::adaptiveThreshold(newspec);
// Calculate JS divergence between new and old spectral frames
if (i > 0) { // otherwise we have no previous frame
m_beatsd.push_back(measureSpecDiff(oldspec, newspec));
// std::cerr << "specdiff: " << m_beatsd[m_beatsd.size()-1] << std::endl;
}
// Copy newspec across to old
for (size_t j = 0; j < m_beatframesize/2; ++j) {
oldspec[j] = newspec[j];
}
}
// We now have all spectral difference measures in specdiff
int timesig = m_bpb;
if (timesig == 0) timesig = 4;
d_vec_t dbcand(timesig); // downbeat candidates
for (int beat = 0; beat < timesig; ++beat) {
dbcand[beat] = 0;
}
// look for beat transition which leads to greatest spectral change
for (int beat = 0; beat < timesig; ++beat) {
int count = 0;
for (int example = beat-1; example < (int)m_beatsd.size(); example += timesig) {
if (example < 0) continue;
dbcand[beat] += (m_beatsd[example]) / timesig;
++count;
}
if (count > 0) dbcand[beat] /= count;
// std::cerr << "dbcand[" << beat << "] = " << dbcand[beat] << std::endl;
}
// first downbeat is beat at index of maximum value of dbcand
int dbind = MathUtilities::getMax(dbcand);
// remaining downbeats are at timesig intervals from the first
for (int i = dbind; i < (int)beats.size(); i += timesig) {
downbeats.push_back(i);
}
}
double
DownBeat::measureSpecDiff(d_vec_t oldspec, d_vec_t newspec)
{
// JENSEN-SHANNON DIVERGENCE BETWEEN SPECTRAL FRAMES
unsigned int SPECSIZE = 512; // ONLY LOOK AT FIRST 512 SAMPLES OF SPECTRUM.
if (SPECSIZE > oldspec.size()/4) {
SPECSIZE = oldspec.size()/4;
}
double SD = 0.;
double sd1 = 0.;
double sumnew = 0.;
double sumold = 0.;
for (unsigned int i = 0;i < SPECSIZE;i++)
{
newspec[i] +=EPS;
oldspec[i] +=EPS;
sumnew+=newspec[i];
sumold+=oldspec[i];
}
for (unsigned int i = 0;i < SPECSIZE;i++)
{
newspec[i] /= (sumnew);
oldspec[i] /= (sumold);
// IF ANY SPECTRAL VALUES ARE 0 (SHOULDN'T BE ANY!) SET THEM TO 1
if (newspec[i] == 0)
{
newspec[i] = 1.;
}
if (oldspec[i] == 0)
{
oldspec[i] = 1.;
}
// JENSEN-SHANNON CALCULATION
sd1 = 0.5*oldspec[i] + 0.5*newspec[i];
SD = SD + (-sd1*log(sd1)) + (0.5*(oldspec[i]*log(oldspec[i]))) + (0.5*(newspec[i]*log(newspec[i])));
}
return SD;
}
void
DownBeat::getBeatSD(vector<double> &beatsd) const
{
for (int i = 0; i < (int)m_beatsd.size(); ++i) beatsd.push_back(m_beatsd[i]);
}

View File

@ -0,0 +1,135 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2008-2009 Matthew Davies and QMUL.
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 DOWNBEAT_H
#define DOWNBEAT_H
#include <vector>
#include "dsp/rateconversion/Decimator.h"
using std::vector;
class FFTReal;
/**
* This class takes an input audio signal and a sequence of beat
* locations (calculated e.g. by TempoTrackV2) and estimates which of
* the beat locations are downbeats (first beat of the bar).
*
* The input audio signal is expected to have been downsampled to a
* very low sampling rate (e.g. 2700Hz). A utility function for
* downsampling and buffering incoming block-by-block audio is
* provided.
*/
class DownBeat
{
public:
/**
* Construct a downbeat locator that will operate on audio at the
* downsampled by the given decimation factor from the given
* original sample rate, plus beats extracted from the same audio
* at the given original sample rate with the given frame
* increment.
*
* decimationFactor must be a power of two no greater than 64, and
* dfIncrement must be a multiple of decimationFactor.
*/
DownBeat(float originalSampleRate,
size_t decimationFactor,
size_t dfIncrement);
~DownBeat();
void setBeatsPerBar(int bpb);
/**
* Estimate which beats are down-beats.
*
* audio contains the input audio stream after downsampling, and
* audioLength contains the number of samples in this downsampled
* stream.
*
* beats contains a series of beat positions expressed in
* multiples of the df increment at the audio's original sample
* rate, as described to the constructor.
*
* The returned downbeat array contains a series of indices to the
* beats array.
*/
void findDownBeats(const float *audio, // downsampled
size_t audioLength, // after downsampling
const vector<double> &beats,
vector<int> &downbeats);
/**
* Return the beat spectral difference function. This is
* calculated during findDownBeats, so this function can only be
* meaningfully called after that has completed. The returned
* vector contains one value for each of the beat times passed in
* to findDownBeats, less one. Each value contains the spectral
* difference between region prior to the beat's nominal position
* and the region following it.
*/
void getBeatSD(vector<double> &beatsd) const;
/**
* For your downsampling convenience: call this function
* repeatedly with input audio blocks containing dfIncrement
* samples at the original sample rate, to decimate them to the
* downsampled rate and buffer them within the DownBeat class.
*
* Call getBufferedAudio() to retrieve the results after all
* blocks have been processed.
*/
void pushAudioBlock(const float *audio);
/**
* Retrieve the accumulated audio produced by pushAudioBlock calls.
*/
const float *getBufferedAudio(size_t &length) const;
/**
* Clear any buffered downsampled audio data.
*/
void resetAudioBuffer();
private:
typedef vector<int> i_vec_t;
typedef vector<vector<int> > i_mat_t;
typedef vector<double> d_vec_t;
typedef vector<vector<double> > d_mat_t;
void makeDecimators();
double measureSpecDiff(d_vec_t oldspec, d_vec_t newspec);
int m_bpb;
float m_rate;
size_t m_factor;
size_t m_increment;
Decimator *m_decimator1;
Decimator *m_decimator2;
float *m_buffer;
float *m_decbuf;
size_t m_bufsiz;
size_t m_buffill;
size_t m_beatframesize;
double *m_beatframe;
FFTReal *m_fft;
double *m_fftRealOut;
double *m_fftImagOut;
d_vec_t m_beatsd;
};
#endif

View File

@ -0,0 +1,869 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2005-2006 Christian Landone.and Matthew Davies.
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 "TempoTrack.h"
#include "maths/MathAliases.h"
#include "maths/MathUtilities.h"
#include <iostream>
#include <cassert>
//#define DEBUG_TEMPO_TRACK 1
#define RAY43VAL
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
TempoTrack::TempoTrack( TTParams Params )
{
m_tempoScratch = NULL;
m_rawDFFrame = NULL;
m_smoothDFFrame = NULL;
m_frameACF = NULL;
m_smoothRCF = NULL;
m_dataLength = 0;
m_winLength = 0;
m_lagLength = 0;
m_rayparam = 0;
m_sigma = 0;
m_DFWVNnorm = 0;
initialise( Params );
}
TempoTrack::~TempoTrack()
{
deInitialise();
}
void TempoTrack::initialise( TTParams Params )
{
m_winLength = Params.winLength;
m_lagLength = Params.lagLength;
m_rayparam = 43.0;
m_sigma = sqrt(3.9017);
m_DFWVNnorm = exp( ( log( 2.0 ) / m_rayparam ) * ( m_winLength + 2 ) );
m_rawDFFrame = new double[ m_winLength ];
m_smoothDFFrame = new double[ m_winLength ];
m_frameACF = new double[ m_winLength ];
m_tempoScratch = new double[ m_lagLength ];
m_smoothRCF = new double[ m_lagLength ];
unsigned int winPre = Params.WinT.pre;
unsigned int winPost = Params.WinT.post;
m_DFFramer.configure( m_winLength, m_lagLength );
m_DFPParams.length = m_winLength;
m_DFPParams.AlphaNormParam = Params.alpha;
m_DFPParams.LPOrd = Params.LPOrd;
m_DFPParams.LPACoeffs = Params.LPACoeffs;
m_DFPParams.LPBCoeffs = Params.LPBCoeffs;
m_DFPParams.winPre = Params.WinT.pre;
m_DFPParams.winPost = Params.WinT.post;
m_DFPParams.isMedianPositive = true;
m_DFConditioning = new DFProcess( m_DFPParams );
// these are parameters for smoothing m_tempoScratch
m_RCFPParams.length = m_lagLength;
m_RCFPParams.AlphaNormParam = Params.alpha;
m_RCFPParams.LPOrd = Params.LPOrd;
m_RCFPParams.LPACoeffs = Params.LPACoeffs;
m_RCFPParams.LPBCoeffs = Params.LPBCoeffs;
m_RCFPParams.winPre = Params.WinT.pre;
m_RCFPParams.winPost = Params.WinT.post;
m_RCFPParams.isMedianPositive = true;
m_RCFConditioning = new DFProcess( m_RCFPParams );
}
void TempoTrack::deInitialise()
{
delete [] m_rawDFFrame;
delete [] m_smoothDFFrame;
delete [] m_smoothRCF;
delete [] m_frameACF;
delete [] m_tempoScratch;
delete m_DFConditioning;
delete m_RCFConditioning;
}
void TempoTrack::createCombFilter(double* Filter, unsigned int winLength, unsigned int TSig, double beatLag)
{
unsigned int i;
if( beatLag == 0 )
{
for( i = 0; i < winLength; i++ )
{
Filter[ i ] = ( ( i + 1 ) / pow( m_rayparam, 2.0) ) * exp( ( -pow(( i + 1 ),2.0 ) / ( 2.0 * pow( m_rayparam, 2.0))));
}
}
else
{
m_sigma = beatLag/4;
for( i = 0; i < winLength; i++ )
{
double dlag = (double)(i+1) - beatLag;
Filter[ i ] = exp(-0.5 * pow(( dlag / m_sigma), 2.0) ) / (sqrt( 2 * PI) * m_sigma);
}
}
}
double TempoTrack::tempoMM(double* ACF, double* weight, int tsig)
{
double period = 0;
double maxValRCF = 0.0;
unsigned int maxIndexRCF = 0;
double* pdPeaks;
unsigned int maxIndexTemp;
double maxValTemp;
unsigned int count;
unsigned int numelem,i,j;
int a, b;
for( i = 0; i < m_lagLength; i++ )
m_tempoScratch[ i ] = 0.0;
if( tsig == 0 )
{
//if time sig is unknown, use metrically unbiased version of Filterbank
numelem = 4;
}
else
{
numelem = tsig;
}
#ifdef DEBUG_TEMPO_TRACK
std::cerr << "tempoMM: m_winLength = " << m_winLength << ", m_lagLength = " << m_lagLength << ", numelem = " << numelem << std::endl;
#endif
for(i=1;i<m_lagLength-1;i++)
{
//first and last output values are left intentionally as zero
for (a=1;a<=numelem;a++)
{
for(b=(1-a);b<a;b++)
{
if( tsig == 0 )
{
m_tempoScratch[i] += ACF[a*(i+1)+b-1] * (1.0 / (2.0 * (double)a-1)) * weight[i];
}
else
{
m_tempoScratch[i] += ACF[a*(i+1)+b-1] * 1 * weight[i];
}
}
}
}
//////////////////////////////////////////////////
// MODIFIED BEAT PERIOD EXTRACTION //////////////
/////////////////////////////////////////////////
// find smoothed version of RCF ( as applied to Detection Function)
m_RCFConditioning->process( m_tempoScratch, m_smoothRCF);
if (tsig != 0) // i.e. in context dependent state
{
// NOW FIND MAX INDEX OF ACFOUT
for( i = 0; i < m_lagLength; i++)
{
if( m_tempoScratch[ i ] > maxValRCF)
{
maxValRCF = m_tempoScratch[ i ];
maxIndexRCF = i;
}
}
}
else // using rayleigh weighting
{
vector <vector<double> > rcfMat;
double sumRcf = 0.;
double maxVal = 0.;
// now find the two values which minimise rcfMat
double minVal = 0.;
int p_i = 1; // periodicity for row i;
int p_j = 1; //periodicity for column j;
for ( i=0; i<m_lagLength; i++)
{
m_tempoScratch[i] =m_smoothRCF[i];
}
// normalise m_tempoScratch so that it sums to zero.
for ( i=0; i<m_lagLength; i++)
{
sumRcf += m_tempoScratch[i];
}
for( i=0; i<m_lagLength; i++)
{
m_tempoScratch[i] /= sumRcf;
}
// create a matrix to store m_tempoScratchValues modified by log2 ratio
for ( i=0; i<m_lagLength; i++)
{
rcfMat.push_back ( vector<double>() ); // adds a new row...
}
for (i=0; i<m_lagLength; i++)
{
for (j=0; j<m_lagLength; j++)
{
rcfMat[i].push_back (0.);
}
}
// the 'i' and 'j' indices deliberately start from '1' and not '0'
for ( i=1; i<m_lagLength; i++)
{
for (j=1; j<m_lagLength; j++)
{
double log2PeriodRatio = log( static_cast<double>(i)/static_cast<double>(j) ) / log(2.0);
rcfMat[i][j] = ( abs(1.0-abs(log2PeriodRatio)) );
rcfMat[i][j] += ( 0.01*( 1./(m_tempoScratch[i]+m_tempoScratch[j]) ) );
}
}
// set diagonal equal to maximum value in rcfMat
// we don't want to pick one strong middle peak - we need a combination of two peaks.
for ( i=1; i<m_lagLength; i++)
{
for (j=1; j<m_lagLength; j++)
{
if (rcfMat[i][j] > maxVal)
{
maxVal = rcfMat[i][j];
}
}
}
for ( i=1; i<m_lagLength; i++)
{
rcfMat[i][i] = maxVal;
}
// now find the row and column number which minimise rcfMat
minVal = maxVal;
for ( i=1; i<m_lagLength; i++)
{
for ( j=1; j<m_lagLength; j++)
{
if (rcfMat[i][j] < minVal)
{
minVal = rcfMat[i][j];
p_i = i;
p_j = j;
}
}
}
// initially choose p_j (arbitrary) - saves on an else statement
int beatPeriod = p_j;
if (m_tempoScratch[p_i] > m_tempoScratch[p_j])
{
beatPeriod = p_i;
}
// now write the output
maxIndexRCF = static_cast<int>(beatPeriod);
}
double locked = 5168.f / maxIndexRCF;
if (locked >= 30 && locked <= 180) {
m_lockedTempo = locked;
}
#ifdef DEBUG_TEMPO_TRACK
std::cerr << "tempoMM: locked tempo = " << m_lockedTempo << std::endl;
#endif
if( tsig == 0 )
tsig = 4;
#ifdef DEBUG_TEMPO_TRACK
std::cerr << "tempoMM: maxIndexRCF = " << maxIndexRCF << std::endl;
#endif
if( tsig == 4 )
{
#ifdef DEBUG_TEMPO_TRACK
std::cerr << "tsig == 4" << std::endl;
#endif
pdPeaks = new double[ 4 ];
for( i = 0; i < 4; i++ ){ pdPeaks[ i ] = 0.0;}
pdPeaks[ 0 ] = ( double )maxIndexRCF + 1;
maxIndexTemp = 0;
maxValTemp = 0.0;
count = 0;
for( i = (2 * maxIndexRCF + 1) - 1; i < (2 * maxIndexRCF + 1) + 2; i++ )
{
if( ACF[ i ] > maxValTemp )
{
maxValTemp = ACF[ i ];
maxIndexTemp = count;
}
count++;
}
pdPeaks[ 1 ] = (double)( maxIndexTemp + 1 + ( (2 * maxIndexRCF + 1 ) - 2 ) + 1 )/2;
maxIndexTemp = 0;
maxValTemp = 0.0;
count = 0;
for( i = (3 * maxIndexRCF + 2 ) - 2; i < (3 * maxIndexRCF + 2 ) + 3; i++ )
{
if( ACF[ i ] > maxValTemp )
{
maxValTemp = ACF[ i ];
maxIndexTemp = count;
}
count++;
}
pdPeaks[ 2 ] = (double)( maxIndexTemp + 1 + ( (3 * maxIndexRCF + 2) - 4 ) + 1 )/3;
maxIndexTemp = 0;
maxValTemp = 0.0;
count = 0;
for( i = ( 4 * maxIndexRCF + 3) - 3; i < ( 4 * maxIndexRCF + 3) + 4; i++ )
{
if( ACF[ i ] > maxValTemp )
{
maxValTemp = ACF[ i ];
maxIndexTemp = count;
}
count++;
}
pdPeaks[ 3 ] = (double)( maxIndexTemp + 1 + ( (4 * maxIndexRCF + 3) - 9 ) + 1 )/4 ;
period = MathUtilities::mean( pdPeaks, 4 );
}
else
{
#ifdef DEBUG_TEMPO_TRACK
std::cerr << "tsig != 4" << std::endl;
#endif
pdPeaks = new double[ 3 ];
for( i = 0; i < 3; i++ ){ pdPeaks[ i ] = 0.0;}
pdPeaks[ 0 ] = ( double )maxIndexRCF + 1;
maxIndexTemp = 0;
maxValTemp = 0.0;
count = 0;
for( i = (2 * maxIndexRCF + 1) - 1; i < (2 * maxIndexRCF + 1) + 2; i++ )
{
if( ACF[ i ] > maxValTemp )
{
maxValTemp = ACF[ i ];
maxIndexTemp = count;
}
count++;
}
pdPeaks[ 1 ] = (double)( maxIndexTemp + 1 + ( (2 * maxIndexRCF + 1 ) - 2 ) + 1 )/2;
maxIndexTemp = 0;
maxValTemp = 0.0;
count = 0;
for( i = (3 * maxIndexRCF + 2 ) - 2; i < (3 * maxIndexRCF + 2 ) + 3; i++ )
{
if( ACF[ i ] > maxValTemp )
{
maxValTemp = ACF[ i ];
maxIndexTemp = count;
}
count++;
}
pdPeaks[ 2 ] = (double)( maxIndexTemp + 1 + ( (3 * maxIndexRCF + 2) - 4 ) + 1 )/3;
period = MathUtilities::mean( pdPeaks, 3 );
}
delete [] pdPeaks;
return period;
}
void TempoTrack::stepDetect( double* periodP, double* periodG, int currentIdx, int* flag )
{
double stepthresh = 1 * 3.9017;
if( *flag )
{
if(abs(periodG[ currentIdx ] - periodP[ currentIdx ]) > stepthresh)
{
// do nuffin'
}
}
else
{
if(fabs(periodG[ currentIdx ]-periodP[ currentIdx ]) > stepthresh)
{
*flag = 3;
}
}
}
void TempoTrack::constDetect( double* periodP, int currentIdx, int* flag )
{
double constthresh = 2 * 3.9017;
if( fabs( 2 * periodP[ currentIdx ] - periodP[ currentIdx - 1] - periodP[ currentIdx - 2] ) < constthresh)
{
*flag = 1;
}
else
{
*flag = 0;
}
}
int TempoTrack::findMeter(double *ACF, unsigned int len, double period)
{
int i;
int p = (int)MathUtilities::round( period );
int tsig;
double Energy_3 = 0.0;
double Energy_4 = 0.0;
double temp3A = 0.0;
double temp3B = 0.0;
double temp4A = 0.0;
double temp4B = 0.0;
double* dbf = new double[ len ]; int t = 0;
for( unsigned int u = 0; u < len; u++ ){ dbf[ u ] = 0.0; }
if( (double)len < 6 * p + 2 )
{
for( i = ( 3 * p - 2 ); i < ( 3 * p + 2 ) + 1; i++ )
{
temp3A += ACF[ i ];
dbf[ t++ ] = ACF[ i ];
}
for( i = ( 4 * p - 2 ); i < ( 4 * p + 2 ) + 1; i++ )
{
temp4A += ACF[ i ];
}
Energy_3 = temp3A;
Energy_4 = temp4A;
}
else
{
for( i = ( 3 * p - 2 ); i < ( 3 * p + 2 ) + 1; i++ )
{
temp3A += ACF[ i ];
}
for( i = ( 4 * p - 2 ); i < ( 4 * p + 2 ) + 1; i++ )
{
temp4A += ACF[ i ];
}
for( i = ( 6 * p - 2 ); i < ( 6 * p + 2 ) + 1; i++ )
{
temp3B += ACF[ i ];
}
for( i = ( 2 * p - 2 ); i < ( 2 * p + 2 ) + 1; i++ )
{
temp4B += ACF[ i ];
}
Energy_3 = temp3A + temp3B;
Energy_4 = temp4A + temp4B;
}
if (Energy_3 > Energy_4)
{
tsig = 3;
}
else
{
tsig = 4;
}
return tsig;
}
void TempoTrack::createPhaseExtractor(double *Filter, unsigned int winLength, double period, unsigned int fsp, unsigned int lastBeat)
{
int p = (int)MathUtilities::round( period );
int predictedOffset = 0;
#ifdef DEBUG_TEMPO_TRACK
std::cerr << "TempoTrack::createPhaseExtractor: period = " << period << ", p = " << p << std::endl;
#endif
if (p > 10000) {
std::cerr << "TempoTrack::createPhaseExtractor: WARNING! Highly implausible period value " << p << "!" << std::endl;
period = 5168 / 120;
}
double* phaseScratch = new double[ p*2 + 2 ];
for (int i = 0; i < p*2 + 2; ++i) phaseScratch[i] = 0.0;
if( lastBeat != 0 )
{
lastBeat = (int)MathUtilities::round((double)lastBeat );///(double)winLength);
predictedOffset = lastBeat + p - fsp;
if (predictedOffset < 0)
{
lastBeat = 0;
}
}
if( lastBeat != 0 )
{
int mu = p;
double sigma = (double)p/8;
double PhaseMin = 0.0;
double PhaseMax = 0.0;
unsigned int scratchLength = p*2;
double temp = 0.0;
for( int i = 0; i < scratchLength; i++ )
{
phaseScratch[ i ] = exp( -0.5 * pow( ( i - mu ) / sigma, 2 ) ) / ( sqrt( 2*PI ) *sigma );
}
MathUtilities::getFrameMinMax( phaseScratch, scratchLength, &PhaseMin, &PhaseMax );
for(int i = 0; i < scratchLength; i ++)
{
temp = phaseScratch[ i ];
phaseScratch[ i ] = (temp - PhaseMin)/PhaseMax;
}
#ifdef DEBUG_TEMPO_TRACK
std::cerr << "predictedOffset = " << predictedOffset << std::endl;
#endif
unsigned int index = 0;
for (int i = p - ( predictedOffset - 1); i < p + ( p - predictedOffset) + 1; i++)
{
#ifdef DEBUG_TEMPO_TRACK
std::cerr << "assigning to filter index " << index << " (size = " << p*2 << ")" << " value " << phaseScratch[i] << " from scratch index " << i << std::endl;
#endif
Filter[ index++ ] = phaseScratch[ i ];
}
}
else
{
for( int i = 0; i < p; i ++)
{
Filter[ i ] = 1;
}
}
delete [] phaseScratch;
}
int TempoTrack::phaseMM(double *DF, double *weighting, unsigned int winLength, double period)
{
int alignment = 0;
int p = (int)MathUtilities::round( period );
double temp = 0.0;
double* y = new double[ winLength ];
double* align = new double[ p ];
for( int i = 0; i < winLength; i++ )
{
y[ i ] = (double)( -i + winLength )/(double)winLength;
y[ i ] = pow(y [i ],2.0); // raise to power 2.
}
for( int o = 0; o < p; o++ )
{
temp = 0.0;
for(int i = 1 + (o - 1); i< winLength; i += (p + 1))
{
temp = temp + DF[ i ] * y[ i ];
}
align[ o ] = temp * weighting[ o ];
}
double valTemp = 0.0;
for(int i = 0; i < p; i++)
{
if( align[ i ] > valTemp )
{
valTemp = align[ i ];
alignment = i;
}
}
delete [] y;
delete [] align;
return alignment;
}
int TempoTrack::beatPredict(unsigned int FSP0, double alignment, double period, unsigned int step )
{
int beat = 0;
int p = (int)MathUtilities::round( period );
int align = (int)MathUtilities::round( alignment );
int FSP = (int)MathUtilities::round( FSP0 );
int FEP = FSP + ( step );
beat = FSP + align;
m_beats.push_back( beat );
while( beat + p < FEP )
{
beat += p;
m_beats.push_back( beat );
}
return beat;
}
vector<int> TempoTrack::process( vector <double> DF,
vector <double> *tempoReturn )
{
m_dataLength = DF.size();
m_lockedTempo = 0.0;
double period = 0.0;
int stepFlag = 0;
int constFlag = 0;
int FSP = 0;
int tsig = 0;
int lastBeat = 0;
vector <double> causalDF;
causalDF = DF;
//Prepare Causal Extension DFData
unsigned int DFCLength = m_dataLength + m_winLength;
for( unsigned int j = 0; j < m_winLength; j++ )
{
causalDF.push_back( 0 );
}
double* RW = new double[ m_lagLength ];
for( unsigned int clear = 0; clear < m_lagLength; clear++){ RW[ clear ] = 0.0;}
double* GW = new double[ m_lagLength ];
for(unsigned int clear = 0; clear < m_lagLength; clear++){ GW[ clear ] = 0.0;}
double* PW = new double[ m_lagLength ];
for(unsigned clear = 0; clear < m_lagLength; clear++){ PW[ clear ] = 0.0;}
m_DFFramer.setSource( &causalDF[0], m_dataLength );
unsigned int TTFrames = m_DFFramer.getMaxNoFrames();
#ifdef DEBUG_TEMPO_TRACK
std::cerr << "TTFrames = " << TTFrames << std::endl;
#endif
double* periodP = new double[ TTFrames ];
for(unsigned clear = 0; clear < TTFrames; clear++){ periodP[ clear ] = 0.0;}
double* periodG = new double[ TTFrames ];
for(unsigned clear = 0; clear < TTFrames; clear++){ periodG[ clear ] = 0.0;}
double* alignment = new double[ TTFrames ];
for(unsigned clear = 0; clear < TTFrames; clear++){ alignment[ clear ] = 0.0;}
m_beats.clear();
createCombFilter( RW, m_lagLength, 0, 0 );
int TTLoopIndex = 0;
for( unsigned int i = 0; i < TTFrames; i++ )
{
m_DFFramer.getFrame( m_rawDFFrame );
m_DFConditioning->process( m_rawDFFrame, m_smoothDFFrame );
m_correlator.doAutoUnBiased( m_smoothDFFrame, m_frameACF, m_winLength );
periodP[ TTLoopIndex ] = tempoMM( m_frameACF, RW, 0 );
if( GW[ 0 ] != 0 )
{
periodG[ TTLoopIndex ] = tempoMM( m_frameACF, GW, tsig );
}
else
{
periodG[ TTLoopIndex ] = 0.0;
}
stepDetect( periodP, periodG, TTLoopIndex, &stepFlag );
if( stepFlag == 1)
{
constDetect( periodP, TTLoopIndex, &constFlag );
stepFlag = 0;
}
else
{
stepFlag -= 1;
}
if( stepFlag < 0 )
{
stepFlag = 0;
}
if( constFlag != 0)
{
tsig = findMeter( m_frameACF, m_winLength, periodP[ TTLoopIndex ] );
createCombFilter( GW, m_lagLength, tsig, periodP[ TTLoopIndex ] );
periodG[ TTLoopIndex ] = tempoMM( m_frameACF, GW, tsig );
period = periodG[ TTLoopIndex ];
#ifdef DEBUG_TEMPO_TRACK
std::cerr << "TempoTrack::process: constFlag == " << constFlag << ", TTLoopIndex = " << TTLoopIndex << ", period from periodG = " << period << std::endl;
#endif
createPhaseExtractor( PW, m_winLength, period, FSP, 0 );
constFlag = 0;
}
else
{
if( GW[ 0 ] != 0 )
{
period = periodG[ TTLoopIndex ];
#ifdef DEBUG_TEMPO_TRACK
std::cerr << "TempoTrack::process: GW[0] == " << GW[0] << ", TTLoopIndex = " << TTLoopIndex << ", period from periodG = " << period << std::endl;
#endif
if (period > 10000) {
std::cerr << "TempoTrack::process: WARNING! Highly implausible period value " << period << "!" << std::endl;
std::cerr << "periodG contains (of " << TTFrames << " frames): " << std::endl;
for (int i = 0; i < TTLoopIndex + 3 && i < TTFrames; ++i) {
std::cerr << i << " -> " << periodG[i] << std::endl;
}
std::cerr << "periodP contains (of " << TTFrames << " frames): " << std::endl;
for (int i = 0; i < TTLoopIndex + 3 && i < TTFrames; ++i) {
std::cerr << i << " -> " << periodP[i] << std::endl;
}
period = 5168 / 120;
}
createPhaseExtractor( PW, m_winLength, period, FSP, lastBeat );
}
else
{
period = periodP[ TTLoopIndex ];
#ifdef DEBUG_TEMPO_TRACK
std::cerr << "TempoTrack::process: GW[0] == " << GW[0] << ", TTLoopIndex = " << TTLoopIndex << ", period from periodP = " << period << std::endl;
#endif
createPhaseExtractor( PW, m_winLength, period, FSP, 0 );
}
}
alignment[ TTLoopIndex ] = phaseMM( m_rawDFFrame, PW, m_winLength, period );
lastBeat = beatPredict(FSP, alignment[ TTLoopIndex ], period, m_lagLength );
FSP += (m_lagLength);
if (tempoReturn) tempoReturn->push_back(m_lockedTempo);
TTLoopIndex++;
}
delete [] periodP;
delete [] periodG;
delete [] alignment;
delete [] RW;
delete [] GW;
delete [] PW;
return m_beats;
}

View File

@ -0,0 +1,111 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 TEMPOTRACK_H
#define TEMPOTRACK_H
#include <stdio.h>
#include <vector>
#include "dsp/signalconditioning/DFProcess.h"
#include "maths/Correlation.h"
#include "dsp/signalconditioning/Framer.h"
using std::vector;
struct WinThresh
{
unsigned int pre;
unsigned int post;
};
struct TTParams
{
unsigned int winLength; //Analysis window length
unsigned int lagLength; //Lag & Stride size
unsigned int alpha; //alpha-norm parameter
unsigned int LPOrd; // low-pass Filter order
double* LPACoeffs; //low pass Filter den coefficients
double* LPBCoeffs; //low pass Filter num coefficients
WinThresh WinT;//window size in frames for adaptive thresholding [pre post]:
};
class TempoTrack
{
public:
TempoTrack( TTParams Params );
virtual ~TempoTrack();
vector<int> process( vector <double> DF, vector <double> *tempoReturn = 0);
private:
void initialise( TTParams Params );
void deInitialise();
int beatPredict( unsigned int FSP, double alignment, double period, unsigned int step);
int phaseMM( double* DF, double* weighting, unsigned int winLength, double period );
void createPhaseExtractor( double* Filter, unsigned int winLength, double period, unsigned int fsp, unsigned int lastBeat );
int findMeter( double* ACF, unsigned int len, double period );
void constDetect( double* periodP, int currentIdx, int* flag );
void stepDetect( double* periodP, double* periodG, int currentIdx, int* flag );
void createCombFilter( double* Filter, unsigned int winLength, unsigned int TSig, double beatLag );
double tempoMM( double* ACF, double* weight, int sig );
unsigned int m_dataLength;
unsigned int m_winLength;
unsigned int m_lagLength;
double m_rayparam;
double m_sigma;
double m_DFWVNnorm;
vector<int> m_beats; // Vector of detected beats
double m_lockedTempo;
double* m_tempoScratch;
double* m_smoothRCF; // Smoothed Output of Comb Filterbank (m_tempoScratch)
// Processing Buffers
double* m_rawDFFrame; // Original Detection Function Analysis Frame
double* m_smoothDFFrame; // Smoothed Detection Function Analysis Frame
double* m_frameACF; // AutoCorrelation of Smoothed Detection Function
//Low Pass Coefficients for DF Smoothing
double* m_ACoeffs;
double* m_BCoeffs;
// Objetcs/operators declaration
Framer m_DFFramer;
DFProcess* m_DFConditioning;
Correlation m_correlator;
// Config structure for DFProcess
DFProcConfig m_DFPParams;
// also want to smooth m_tempoScratch
DFProcess* m_RCFConditioning;
// Config structure for RCFProcess
DFProcConfig m_RCFPParams;
};
#endif

View File

@ -0,0 +1,487 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2008-2009 Matthew Davies and QMUL.
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 "TempoTrackV2.h"
#include <cmath>
#include <cstdlib>
#include <iostream>
#include "maths/MathUtilities.h"
#define EPS 0.0000008 // just some arbitrary small number
TempoTrackV2::TempoTrackV2(float rate, size_t increment) :
m_rate(rate), m_increment(increment) { }
TempoTrackV2::~TempoTrackV2() { }
void
TempoTrackV2::filter_df(d_vec_t &df)
{
d_vec_t a(3);
d_vec_t b(3);
d_vec_t lp_df(df.size());
//equivalent in matlab to [b,a] = butter(2,0.4);
a[0] = 1.0000;
a[1] = -0.3695;
a[2] = 0.1958;
b[0] = 0.2066;
b[1] = 0.4131;
b[2] = 0.2066;
double inp1 = 0.;
double inp2 = 0.;
double out1 = 0.;
double out2 = 0.;
// forwards filtering
for (unsigned int i = 0;i < df.size();i++)
{
lp_df[i] = b[0]*df[i] + b[1]*inp1 + b[2]*inp2 - a[1]*out1 - a[2]*out2;
inp2 = inp1;
inp1 = df[i];
out2 = out1;
out1 = lp_df[i];
}
// copy forwards filtering to df...
// but, time-reversed, ready for backwards filtering
for (unsigned int i = 0;i < df.size();i++)
{
df[i] = lp_df[df.size()-i-1];
}
for (unsigned int i = 0;i < df.size();i++)
{
lp_df[i] = 0.;
}
inp1 = 0.; inp2 = 0.;
out1 = 0.; out2 = 0.;
// backwards filetering on time-reversed df
for (unsigned int i = 0;i < df.size();i++)
{
lp_df[i] = b[0]*df[i] + b[1]*inp1 + b[2]*inp2 - a[1]*out1 - a[2]*out2;
inp2 = inp1;
inp1 = df[i];
out2 = out1;
out1 = lp_df[i];
}
// write the re-reversed (i.e. forward) version back to df
for (unsigned int i = 0;i < df.size();i++)
{
df[i] = lp_df[df.size()-i-1];
}
}
void
TempoTrackV2::calculateBeatPeriod(const vector<double> &df,
vector<double> &beat_period,
vector<double> &tempi)
{
// to follow matlab.. split into 512 sample frames with a 128 hop size
// calculate the acf,
// then the rcf.. and then stick the rcfs as columns of a matrix
// then call viterbi decoding with weight vector and transition matrix
// and get best path
unsigned int wv_len = 128;
double rayparam = 43.;
// make rayleigh weighting curve
d_vec_t wv(wv_len);
for (unsigned int i=0; i<wv.size(); i++)
{
wv[i] = (static_cast<double> (i) / pow(rayparam,2.)) * exp((-1.*pow(-static_cast<double> (i),2.)) / (2.*pow(rayparam,2.)));
}
// beat tracking frame size (roughly 6 seconds) and hop (1.5 seconds)
unsigned int winlen = 512;
unsigned int step = 128;
// matrix to store output of comb filter bank, increment column of matrix at each frame
d_mat_t rcfmat;
int col_counter = -1;
// main loop for beat period calculation
for (unsigned int i=0; i+winlen<df.size(); i+=step)
{
// get dfframe
d_vec_t dfframe(winlen);
for (unsigned int k=0; k<winlen; k++)
{
dfframe[k] = df[i+k];
}
// get rcf vector for current frame
d_vec_t rcf(wv_len);
get_rcf(dfframe,wv,rcf);
rcfmat.push_back( d_vec_t() ); // adds a new column
col_counter++;
for (unsigned int j=0; j<rcf.size(); j++)
{
rcfmat[col_counter].push_back( rcf[j] );
}
}
// now call viterbi decoding function
viterbi_decode(rcfmat,wv,beat_period,tempi);
}
void
TempoTrackV2::get_rcf(const d_vec_t &dfframe_in, const d_vec_t &wv, d_vec_t &rcf)
{
// calculate autocorrelation function
// then rcf
// just hard code for now... don't really need separate functions to do this
// make acf
d_vec_t dfframe(dfframe_in);
MathUtilities::adaptiveThreshold(dfframe);
d_vec_t acf(dfframe.size());
for (unsigned int lag=0; lag<dfframe.size(); lag++)
{
double sum = 0.;
double tmp = 0.;
for (unsigned int n=0; n<(dfframe.size()-lag); n++)
{
tmp = dfframe[n] * dfframe[n+lag];
sum += tmp;
}
acf[lag] = static_cast<double> (sum/ (dfframe.size()-lag));
}
// now apply comb filtering
int numelem = 4;
for (unsigned int i = 2;i < rcf.size();i++) // max beat period
{
for (int a = 1;a <= numelem;a++) // number of comb elements
{
for (int b = 1-a;b <= a-1;b++) // general state using normalisation of comb elements
{
rcf[i-1] += ( acf[(a*i+b)-1]*wv[i-1] ) / (2.*a-1.); // calculate value for comb filter row
}
}
}
// apply adaptive threshold to rcf
MathUtilities::adaptiveThreshold(rcf);
double rcfsum =0.;
for (unsigned int i=0; i<rcf.size(); i++)
{
rcf[i] += EPS ;
rcfsum += rcf[i];
}
// normalise rcf to sum to unity
for (unsigned int i=0; i<rcf.size(); i++)
{
rcf[i] /= (rcfsum + EPS);
}
}
void
TempoTrackV2::viterbi_decode(const d_mat_t &rcfmat, const d_vec_t &wv, d_vec_t &beat_period, d_vec_t &tempi)
{
// following Kevin Murphy's Viterbi decoding to get best path of
// beat periods through rfcmat
// make transition matrix
d_mat_t tmat;
for (unsigned int i=0;i<wv.size();i++)
{
tmat.push_back ( d_vec_t() ); // adds a new column
for (unsigned int j=0; j<wv.size(); j++)
{
tmat[i].push_back(0.); // fill with zeros initially
}
}
// variance of Gaussians in transition matrix
// formed of Gaussians on diagonal - implies slow tempo change
double sigma = 8.;
// don't want really short beat periods, or really long ones
for (unsigned int i=20;i <wv.size()-20; i++)
{
for (unsigned int j=20; j<wv.size()-20; j++)
{
double mu = static_cast<double>(i);
tmat[i][j] = exp( (-1.*pow((j-mu),2.)) / (2.*pow(sigma,2.)) );
}
}
// parameters for Viterbi decoding... this part is taken from
// Murphy's matlab
d_mat_t delta;
i_mat_t psi;
for (unsigned int i=0;i <rcfmat.size(); i++)
{
delta.push_back( d_vec_t());
psi.push_back( i_vec_t());
for (unsigned int j=0; j<rcfmat[i].size(); j++)
{
delta[i].push_back(0.); // fill with zeros initially
psi[i].push_back(0); // fill with zeros initially
}
}
unsigned int T = delta.size();
if (T < 2) return; // can't do anything at all meaningful
unsigned int Q = delta[0].size();
// initialize first column of delta
for (unsigned int j=0; j<Q; j++)
{
delta[0][j] = wv[j] * rcfmat[0][j];
psi[0][j] = 0;
}
double deltasum = 0.;
for (unsigned int i=0; i<Q; i++)
{
deltasum += delta[0][i];
}
for (unsigned int i=0; i<Q; i++)
{
delta[0][i] /= (deltasum + EPS);
}
for (unsigned int t=1; t<T; t++)
{
d_vec_t tmp_vec(Q);
for (unsigned int j=0; j<Q; j++)
{
for (unsigned int i=0; i<Q; i++)
{
tmp_vec[i] = delta[t-1][i] * tmat[j][i];
}
delta[t][j] = get_max_val(tmp_vec);
psi[t][j] = get_max_ind(tmp_vec);
delta[t][j] *= rcfmat[t][j];
}
// normalise current delta column
double deltasum = 0.;
for (unsigned int i=0; i<Q; i++)
{
deltasum += delta[t][i];
}
for (unsigned int i=0; i<Q; i++)
{
delta[t][i] /= (deltasum + EPS);
}
}
i_vec_t bestpath(T);
d_vec_t tmp_vec(Q);
for (unsigned int i=0; i<Q; i++)
{
tmp_vec[i] = delta[T-1][i];
}
// find starting point - best beat period for "last" frame
bestpath[T-1] = get_max_ind(tmp_vec);
// backtrace through index of maximum values in psi
for (unsigned int t=T-2; t>0 ;t--)
{
bestpath[t] = psi[t+1][bestpath[t+1]];
}
// weird but necessary hack -- couldn't get above loop to terminate at t >= 0
bestpath[0] = psi[1][bestpath[1]];
unsigned int lastind = 0;
for (unsigned int i=0; i<T; i++)
{
unsigned int step = 128;
for (unsigned int j=0; j<step; j++)
{
lastind = i*step+j;
beat_period[lastind] = bestpath[i];
}
// std::cerr << "bestpath[" << i << "] = " << bestpath[i] << " (used for beat_periods " << i*step << " to " << i*step+step-1 << ")" << std::endl;
}
//fill in the last values...
for (unsigned int i=lastind; i<beat_period.size(); i++)
{
beat_period[i] = beat_period[lastind];
}
for (unsigned int i = 0; i < beat_period.size(); i++)
{
tempi.push_back((60. * m_rate / m_increment)/beat_period[i]);
}
}
double
TempoTrackV2::get_max_val(const d_vec_t &df)
{
double maxval = 0.;
for (unsigned int i=0; i<df.size(); i++)
{
if (maxval < df[i])
{
maxval = df[i];
}
}
return maxval;
}
int
TempoTrackV2::get_max_ind(const d_vec_t &df)
{
double maxval = 0.;
int ind = 0;
for (unsigned int i=0; i<df.size(); i++)
{
if (maxval < df[i])
{
maxval = df[i];
ind = i;
}
}
return ind;
}
void
TempoTrackV2::normalise_vec(d_vec_t &df)
{
double sum = 0.;
for (unsigned int i=0; i<df.size(); i++)
{
sum += df[i];
}
for (unsigned int i=0; i<df.size(); i++)
{
df[i]/= (sum + EPS);
}
}
void
TempoTrackV2::calculateBeats(const vector<double> &df,
const vector<double> &beat_period,
vector<double> &beats)
{
if (df.empty() || beat_period.empty()) return;
d_vec_t cumscore(df.size()); // store cumulative score
i_vec_t backlink(df.size()); // backlink (stores best beat locations at each time instant)
d_vec_t localscore(df.size()); // localscore, for now this is the same as the detection function
for (unsigned int i=0; i<df.size(); i++)
{
localscore[i] = df[i];
backlink[i] = -1;
}
double tightness = 4.;
double alpha = 0.9;
// main loop
for (unsigned int i=0; i<localscore.size(); i++)
{
int prange_min = -2*beat_period[i];
int prange_max = round(-0.5*beat_period[i]);
// transition range
d_vec_t txwt (prange_max - prange_min + 1);
d_vec_t scorecands (txwt.size());
for (unsigned int j=0;j<txwt.size();j++)
{
double mu = static_cast<double> (beat_period[i]);
txwt[j] = exp( -0.5*pow(tightness * log((round(2*mu)-j)/mu),2));
// IF IN THE ALLOWED RANGE, THEN LOOK AT CUMSCORE[I+PRANGE_MIN+J
// ELSE LEAVE AT DEFAULT VALUE FROM INITIALISATION: D_VEC_T SCORECANDS (TXWT.SIZE());
int cscore_ind = i+prange_min+j;
if (cscore_ind >= 0)
{
scorecands[j] = txwt[j] * cumscore[cscore_ind];
}
}
// find max value and index of maximum value
double vv = get_max_val(scorecands);
int xx = get_max_ind(scorecands);
cumscore[i] = alpha*vv + (1.-alpha)*localscore[i];
backlink[i] = i+prange_min+xx;
// std::cerr << "backlink[" << i << "] <= " << backlink[i] << std::endl;
}
// STARTING POINT, I.E. LAST BEAT.. PICK A STRONG POINT IN cumscore VECTOR
d_vec_t tmp_vec;
for (unsigned int i=cumscore.size() - beat_period[beat_period.size()-1] ; i<cumscore.size(); i++)
{
tmp_vec.push_back(cumscore[i]);
}
int startpoint = get_max_ind(tmp_vec) + cumscore.size() - beat_period[beat_period.size()-1] ;
// can happen if no results obtained earlier (e.g. input too short)
if (startpoint >= backlink.size()) startpoint = backlink.size()-1;
// USE BACKLINK TO GET EACH NEW BEAT (TOWARDS THE BEGINNING OF THE FILE)
// BACKTRACKING FROM THE END TO THE BEGINNING.. MAKING SURE NOT TO GO BEFORE SAMPLE 0
i_vec_t ibeats;
ibeats.push_back(startpoint);
// std::cerr << "startpoint = " << startpoint << std::endl;
while (backlink[ibeats.back()] > 0)
{
// std::cerr << "backlink[" << ibeats.back() << "] = " << backlink[ibeats.back()] << std::endl;
int b = ibeats.back();
if (backlink[b] == b) break; // shouldn't happen... haha
ibeats.push_back(backlink[b]);
}
// REVERSE SEQUENCE OF IBEATS AND STORE AS BEATS
for (unsigned int i=0; i<ibeats.size(); i++)
{
beats.push_back( static_cast<double>(ibeats[ibeats.size()-i-1]) );
}
}

View File

@ -0,0 +1,73 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2008-2009 Matthew Davies and QMUL.
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 TEMPOTRACKV2_H
#define TEMPOTRACKV2_H
#include <vector>
using std::vector;
//!!! Question: how far is this actually sample rate dependent? I
// think it does produce plausible results for e.g. 48000 as well as
// 44100, but surely the fixed window sizes and comb filtering will
// make it prefer double or half time when run at e.g. 96000?
class TempoTrackV2
{
public:
/**
* Construct a tempo tracker that will operate on beat detection
* function data calculated from audio at the given sample rate
* with the given frame increment.
*
* Currently the sample rate and increment are used only for the
* conversion from beat frame location to bpm in the tempo array.
*/
TempoTrackV2(float sampleRate, size_t dfIncrement);
~TempoTrackV2();
// Returned beat periods are given in df increment units; tempi in bpm
void calculateBeatPeriod(const vector<double> &df,
vector<double> &beatPeriod,
vector<double> &tempi);
// Returned beat positions are given in df increment units
void calculateBeats(const vector<double> &df,
const vector<double> &beatPeriod,
vector<double> &beats);
private:
typedef vector<int> i_vec_t;
typedef vector<vector<int> > i_mat_t;
typedef vector<double> d_vec_t;
typedef vector<vector<double> > d_mat_t;
float m_rate;
size_t m_increment;
void adapt_thresh(d_vec_t &df);
double mean_array(const d_vec_t &dfin, int start, int end);
void filter_df(d_vec_t &df);
void get_rcf(const d_vec_t &dfframe, const d_vec_t &wv, d_vec_t &rcf);
void viterbi_decode(const d_mat_t &rcfmat, const d_vec_t &wv,
d_vec_t &bp, d_vec_t &tempi);
double get_max_val(const d_vec_t &df);
int get_max_ind(const d_vec_t &df);
void normalise_vec(d_vec_t &df);
};
#endif

View File

@ -0,0 +1,144 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2006 Martin Gasser.
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 "ChangeDetectionFunction.h"
#ifndef PI
#define PI (3.14159265358979232846)
#endif
ChangeDetectionFunction::ChangeDetectionFunction(ChangeDFConfig config) :
m_dFilterSigma(0.0), m_iFilterWidth(0)
{
setFilterWidth(config.smoothingWidth);
}
ChangeDetectionFunction::~ChangeDetectionFunction()
{
}
void ChangeDetectionFunction::setFilterWidth(const int iWidth)
{
m_iFilterWidth = iWidth*2+1;
// it is assumed that the gaussian is 0 outside of +/- FWHM
// => filter width = 2*FWHM = 2*2.3548*sigma
m_dFilterSigma = double(m_iFilterWidth) / double(2*2.3548);
m_vaGaussian.resize(m_iFilterWidth);
double dScale = 1.0 / (m_dFilterSigma*sqrt(2*PI));
for (int x = -(m_iFilterWidth-1)/2; x <= (m_iFilterWidth-1)/2; x++)
{
double w = dScale * std::exp ( -(x*x)/(2*m_dFilterSigma*m_dFilterSigma) );
m_vaGaussian[x + (m_iFilterWidth-1)/2] = w;
}
#ifdef DEBUG_CHANGE_DETECTION_FUNCTION
std::cerr << "Filter sigma: " << m_dFilterSigma << std::endl;
std::cerr << "Filter width: " << m_iFilterWidth << std::endl;
#endif
}
ChangeDistance ChangeDetectionFunction::process(const TCSGram& rTCSGram)
{
ChangeDistance retVal;
retVal.resize(rTCSGram.getSize(), 0.0);
TCSGram smoothedTCSGram;
for (int iPosition = 0; iPosition < rTCSGram.getSize(); iPosition++)
{
int iSkipLower = 0;
int iLowerPos = iPosition - (m_iFilterWidth-1)/2;
int iUpperPos = iPosition + (m_iFilterWidth-1)/2;
if (iLowerPos < 0)
{
iSkipLower = -iLowerPos;
iLowerPos = 0;
}
if (iUpperPos >= rTCSGram.getSize())
{
int iMaxIndex = rTCSGram.getSize() - 1;
iUpperPos = iMaxIndex;
}
TCSVector smoothedVector;
// for every bin of the vector, calculate the smoothed value
for (int iPC = 0; iPC < 6; iPC++)
{
size_t j = 0;
double dSmoothedValue = 0.0;
TCSVector rCV;
for (int i = iLowerPos; i <= iUpperPos; i++)
{
rTCSGram.getTCSVector(i, rCV);
dSmoothedValue += m_vaGaussian[iSkipLower + j++] * rCV[iPC];
}
smoothedVector[iPC] = dSmoothedValue;
}
smoothedTCSGram.addTCSVector(smoothedVector);
}
for (int iPosition = 0; iPosition < rTCSGram.getSize(); iPosition++)
{
/*
TODO: calculate a confidence measure for the current estimation
if the current estimate is not confident enough, look further into the future/the past
e.g., High frequency content, zero crossing rate, spectral flatness
*/
TCSVector nextTCS;
TCSVector previousTCS;
int iWindow = 1;
// while (previousTCS.magnitude() < 0.1 && (iPosition-iWindow) > 0)
{
smoothedTCSGram.getTCSVector(iPosition-iWindow, previousTCS);
// std::cout << previousTCS.magnitude() << std::endl;
iWindow++;
}
iWindow = 1;
// while (nextTCS.magnitude() < 0.1 && (iPosition+iWindow) < (rTCSGram.getSize()-1) )
{
smoothedTCSGram.getTCSVector(iPosition+iWindow, nextTCS);
iWindow++;
}
double distance = 0.0;
// Euclidean distance
for (size_t j = 0; j < 6; j++)
{
distance += std::pow(nextTCS[j] - previousTCS[j], 2.0);
}
retVal[iPosition] = std::pow(distance, 0.5);
}
return retVal;
}

View File

@ -0,0 +1,48 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2006 Martin Gasser.
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 _CHANGEDETECTIONFUNCTION_
#define _CHANGEDETECTIONFUNCTION_
//#define DEBUG_CHANGE_DETECTION_FUNCTION 1
#include "TCSgram.h"
#include <valarray>
using std::valarray;
typedef valarray<double> ChangeDistance;
struct ChangeDFConfig
{
int smoothingWidth;
};
class ChangeDetectionFunction
{
public:
ChangeDetectionFunction(ChangeDFConfig);
~ChangeDetectionFunction();
ChangeDistance process(const TCSGram& rTCSGram);
private:
void setFilterWidth(const int iWidth);
private:
valarray<double> m_vaGaussian;
double m_dFilterSigma;
int m_iFilterWidth;
};
#endif // _CHANGDETECTIONFUNCTION_

View File

@ -0,0 +1,77 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2006 Martin Gasser.
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 "TCSgram.h"
#include <valarray>
#include <cmath>
#include <iostream>
#include <limits>
#include "maths/MathUtilities.h"
TCSGram::TCSGram() :
m_uNumBins(6)
{
}
TCSGram::~TCSGram()
{
}
void TCSGram::getTCSVector(int iPosition, TCSVector& rTCSVector) const
{
if (iPosition < 0)
rTCSVector = TCSVector();
else if (iPosition >= m_VectorList.size())
rTCSVector = TCSVector();
else
rTCSVector = m_VectorList[iPosition].second;
}
long TCSGram::getTime(size_t uPosition) const
{
return m_VectorList[uPosition].first;
}
void TCSGram::addTCSVector(const TCSVector& rTCSVector)
{
size_t uSize = m_VectorList.size();
long lMilliSeconds = static_cast<long>(uSize*m_dFrameDurationMS);
std::pair<long, TCSVector> p;
p.first = lMilliSeconds;
p.second = rTCSVector;
m_VectorList.push_back(p);
}
long TCSGram::getDuration() const
{
size_t uSize = m_VectorList.size();
return static_cast<long>(uSize*m_dFrameDurationMS);
}
void TCSGram::printDebug()
{
vectorlist_t::iterator vectorIterator = m_VectorList.begin();
while (vectorIterator != m_VectorList.end())
{
vectorIterator->second.printDebug();
vectorIterator++;
}
}

View File

@ -0,0 +1,49 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2006 Martin Gasser.
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 _TCSGram_
#define _TCSGram_
#include <vector>
#include <valarray>
#include <utility>
#include "TonalEstimator.h"
typedef std::vector<std::pair<long, TCSVector> > vectorlist_t;
class TCSGram
{
public:
TCSGram();
~TCSGram();
void getTCSVector(int, TCSVector&) const;
void addTCSVector(const TCSVector&);
long getTime(size_t) const;
long getDuration() const;
void printDebug();
int getSize() const { return m_VectorList.size(); }
void reserve(size_t uSize) { m_VectorList.reserve(uSize); }
void clear() { m_VectorList.clear(); }
void setFrameDuration(const double dFrameDurationMS) { m_dFrameDurationMS = dFrameDurationMS; }
void setNumBins(const unsigned int uNumBins) { m_uNumBins = uNumBins; }
void normalize();
protected:
vectorlist_t m_VectorList;
unsigned int m_uNumBins;
double m_dFrameDurationMS;
};
#endif

View File

@ -0,0 +1,103 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2006 Martin Gasser.
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 "TonalEstimator.h"
#include <cmath>
#include <iostream>
#ifndef PI
#define PI (3.14159265358979232846)
#endif
TonalEstimator::TonalEstimator()
{
m_Basis.resize(6);
int i = 0;
// circle of fifths
m_Basis[i].resize(12);
for (int iP = 0; iP < 12; iP++)
{
m_Basis[i][iP] = std::sin( (7.0 / 6.0) * iP * PI);
}
i++;
m_Basis[i].resize(12);
for (int iP = 0; iP < 12; iP++)
{
m_Basis[i][iP] = std::cos( (7.0 / 6.0) * iP * PI);
}
i++;
// circle of major thirds
m_Basis[i].resize(12);
for (int iP = 0; iP < 12; iP++)
{
m_Basis[i][iP] = 0.6 * std::sin( (2.0 / 3.0) * iP * PI);
}
i++;
m_Basis[i].resize(12);
for (int iP = 0; iP < 12; iP++)
{
m_Basis[i][iP] = 0.6 * std::cos( (2.0 / 3.0) * iP * PI);
}
i++;
// circle of minor thirds
m_Basis[i].resize(12);
for (int iP = 0; iP < 12; iP++)
{
m_Basis[i][iP] = 1.1 * std::sin( (3.0 / 2.0) * iP * PI);
}
i++;
m_Basis[i].resize(12);
for (int iP = 0; iP < 12; iP++)
{
m_Basis[i][iP] = 1.1 * std::cos( (3.0 / 2.0) * iP * PI);
}
}
TonalEstimator::~TonalEstimator()
{
}
TCSVector TonalEstimator::transform2TCS(const ChromaVector& rVector)
{
TCSVector vaRetVal;
vaRetVal.resize(6, 0.0);
for (int i = 0; i < 6; i++)
{
for (int iP = 0; iP < 12; iP++)
{
vaRetVal[i] += m_Basis[i][iP] * rVector[iP];
}
}
return vaRetVal;
}

View File

@ -0,0 +1,105 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2006 Martin Gasser.
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 _TONALESTIMATOR_
#define _TONALESTIMATOR_
#include <valarray>
#include <numeric>
#include <algorithm>
#include <iostream>
class ChromaVector : public std::valarray<double>
{
public:
ChromaVector(size_t uSize = 12) : std::valarray<double>()
{ resize(uSize, 0.0f); }
virtual ~ChromaVector() {};
void printDebug()
{
for (int i = 0; i < size(); i++)
{
std::cout << (*this)[i] << ";";
}
std::cout << std::endl;
}
void normalizeL1()
{
// normalize the chroma vector (L1 norm)
double dSum = 0.0;
for (size_t i = 0; i < 12; (dSum += std::abs((*this)[i++]))) ;
for (size_t i = 0; i < 12; dSum > 0.0000001?((*this)[i] /= dSum):(*this)[i]=0.0, i++) ;
}
void clear()
{
for (size_t i = 0; i < 12; ++i) (*this)[i] = 0.0;
}
};
class TCSVector : public std::valarray<double>
{
public:
TCSVector() : std::valarray<double>()
{ resize(6, 0.0f); }
virtual ~TCSVector() {};
void printDebug()
{
for (int i = 0; i < size(); i++)
{
std::cout << (*this)[i] << ";";
}
std::cout << std::endl;
}
double magnitude() const
{
double dMag = 0.0;
for (size_t i = 0; i < 6; i++)
{
dMag += std::pow((*this)[i], 2.0);
}
return std::sqrt(dMag);
}
};
class TonalEstimator
{
public:
TonalEstimator();
virtual ~TonalEstimator();
TCSVector transform2TCS(const ChromaVector& rVector);
protected:
std::valarray< std::valarray<double> > m_Basis;
};
#endif // _TONALESTIMATOR_

View File

@ -0,0 +1,181 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file is based on Don Cross's public domain FFT implementation.
*/
#include "FFT.h"
#include "maths/MathUtilities.h"
#include <cmath>
#include <iostream>
FFT::FFT(unsigned int n) :
m_n(n),
m_private(0)
{
if( !MathUtilities::isPowerOfTwo(m_n) )
{
std::cerr << "ERROR: FFT: Non-power-of-two FFT size "
<< m_n << " not supported in this implementation"
<< std::endl;
return;
}
}
FFT::~FFT()
{
}
FFTReal::FFTReal(unsigned int n) :
m_n(n),
m_private_real(0)
{
m_private_real = new FFT(m_n);
}
FFTReal::~FFTReal()
{
delete (FFT *)m_private_real;
}
void
FFTReal::process(bool inverse,
const double *realIn,
double *realOut, double *imagOut)
{
((FFT *)m_private_real)->process(inverse, realIn, 0, realOut, imagOut);
}
static unsigned int numberOfBitsNeeded(unsigned int p_nSamples)
{
int i;
if( p_nSamples < 2 )
{
return 0;
}
for ( i=0; ; i++ )
{
if( p_nSamples & (1 << i) ) return i;
}
}
static unsigned int reverseBits(unsigned int p_nIndex, unsigned int p_nBits)
{
unsigned int i, rev;
for(i=rev=0; i < p_nBits; i++)
{
rev = (rev << 1) | (p_nIndex & 1);
p_nIndex >>= 1;
}
return rev;
}
void
FFT::process(bool p_bInverseTransform,
const double *p_lpRealIn, const double *p_lpImagIn,
double *p_lpRealOut, double *p_lpImagOut)
{
if (!p_lpRealIn || !p_lpRealOut || !p_lpImagOut) return;
// std::cerr << "FFT::process(" << m_n << "," << p_bInverseTransform << ")" << std::endl;
unsigned int NumBits;
unsigned int i, j, k, n;
unsigned int BlockSize, BlockEnd;
double angle_numerator = 2.0 * M_PI;
double tr, ti;
if( !MathUtilities::isPowerOfTwo(m_n) )
{
std::cerr << "ERROR: FFT::process: Non-power-of-two FFT size "
<< m_n << " not supported in this implementation"
<< std::endl;
return;
}
if( p_bInverseTransform ) angle_numerator = -angle_numerator;
NumBits = numberOfBitsNeeded ( m_n );
for( i=0; i < m_n; i++ )
{
j = reverseBits ( i, NumBits );
p_lpRealOut[j] = p_lpRealIn[i];
p_lpImagOut[j] = (p_lpImagIn == 0) ? 0.0 : p_lpImagIn[i];
}
BlockEnd = 1;
for( BlockSize = 2; BlockSize <= m_n; BlockSize <<= 1 )
{
double delta_angle = angle_numerator / (double)BlockSize;
double sm2 = -sin ( -2 * delta_angle );
double sm1 = -sin ( -delta_angle );
double cm2 = cos ( -2 * delta_angle );
double cm1 = cos ( -delta_angle );
double w = 2 * cm1;
double ar[3], ai[3];
for( i=0; i < m_n; i += BlockSize )
{
ar[2] = cm2;
ar[1] = cm1;
ai[2] = sm2;
ai[1] = sm1;
for ( j=i, n=0; n < BlockEnd; j++, n++ )
{
ar[0] = w*ar[1] - ar[2];
ar[2] = ar[1];
ar[1] = ar[0];
ai[0] = w*ai[1] - ai[2];
ai[2] = ai[1];
ai[1] = ai[0];
k = j + BlockEnd;
tr = ar[0]*p_lpRealOut[k] - ai[0]*p_lpImagOut[k];
ti = ar[0]*p_lpImagOut[k] + ai[0]*p_lpRealOut[k];
p_lpRealOut[k] = p_lpRealOut[j] - tr;
p_lpImagOut[k] = p_lpImagOut[j] - ti;
p_lpRealOut[j] += tr;
p_lpImagOut[j] += ti;
}
}
BlockEnd = BlockSize;
}
if( p_bInverseTransform )
{
double denom = (double)m_n;
for ( i=0; i < m_n; i++ )
{
p_lpRealOut[i] /= denom;
p_lpImagOut[i] /= denom;
}
}
}

View File

@ -0,0 +1,42 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
*/
#ifndef FFT_H
#define FFT_H
class FFT
{
public:
FFT(unsigned int nsamples);
virtual ~FFT();
void process(bool inverse,
const double *realIn, const double *imagIn,
double *realOut, double *imagOut);
private:
unsigned int m_n;
void *m_private;
};
class FFTReal
{
public:
FFTReal(unsigned int nsamples);
~FFTReal();
void process(bool inverse,
const double *realIn,
double *realOut, double *imagOut);
private:
unsigned int m_n;
void *m_private_real;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2009 Thomas Wilmering.
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 _WAVELET_H_
#define _WAVELET_H_
#include <string>
#include <vector>
class Wavelet
{
public:
enum Type {
Haar = 0,
Daubechies_2,
Daubechies_3,
Daubechies_4,
Daubechies_5,
Daubechies_6,
Daubechies_7,
Daubechies_8,
Daubechies_9,
Daubechies_10,
Daubechies_20,
Daubechies_40,
Symlet_2,
Symlet_3,
Symlet_4,
Symlet_5,
Symlet_6,
Symlet_7,
Symlet_8,
Symlet_9,
Symlet_10,
Symlet_20,
Symlet_30,
Coiflet_1,
Coiflet_2,
Coiflet_3,
Coiflet_4,
Coiflet_5,
Biorthogonal_1_3,
Biorthogonal_1_5,
Biorthogonal_2_2,
Biorthogonal_2_4,
Biorthogonal_2_6,
Biorthogonal_2_8,
Biorthogonal_3_1,
Biorthogonal_3_3,
Biorthogonal_3_5,
Biorthogonal_3_7,
Biorthogonal_3_9,
Biorthogonal_4_4,
Biorthogonal_5_5,
Biorthogonal_6_8,
Meyer,
LastType = Meyer
};
static std::string getWaveletName(Type);
static void createDecompositionFilters(Type,
std::vector<float> &lpd,
std::vector<float> &hpd);
};
#endif

837
libs/qm-dsp/hmm/hmm.c Normal file
View File

@ -0,0 +1,837 @@
/*
* hmm.c
*
* Created by Mark Levy on 12/02/2006.
* Copyright 2006 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 <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <float.h>
#include <time.h> /* to seed random number generator */
#include <clapack.h> /* LAPACK for matrix inversion */
#include "maths/nan-inf.h"
#ifdef ATLAS_ORDER
#define HAVE_ATLAS 1
#endif
#ifdef HAVE_ATLAS
// Using ATLAS C interface to LAPACK
#define dgetrf_(m, n, a, lda, ipiv, info) \
clapack_dgetrf(CblasColMajor, *m, *n, a, *lda, ipiv)
#define dgetri_(n, a, lda, ipiv, work, lwork, info) \
clapack_dgetri(CblasColMajor, *n, a, *lda, ipiv)
#endif
#ifdef _MAC_OS_X
#include <vecLib/cblas.h>
#else
#include <cblas.h> /* BLAS for matrix multiplication */
#endif
#include "hmm.h"
model_t* hmm_init(double** x, int T, int L, int N)
{
int i, j, d, e, t;
double s, ss;
model_t* model;
model = (model_t*) malloc(sizeof(model_t));
model->N = N;
model->L = L;
model->p0 = (double*) malloc(N*sizeof(double));
model->a = (double**) malloc(N*sizeof(double*));
model->mu = (double**) malloc(N*sizeof(double*));
for (i = 0; i < N; i++)
{
model->a[i] = (double*) malloc(N*sizeof(double));
model->mu[i] = (double*) malloc(L*sizeof(double));
}
model->cov = (double**) malloc(L*sizeof(double*));
for (i = 0; i < L; i++)
model->cov[i] = (double*) malloc(L*sizeof(double));
srand(time(0));
double* global_mean = (double*) malloc(L*sizeof(double));
/* find global mean */
for (d = 0; d < L; d++)
{
global_mean[d] = 0;
for (t = 0; t < T; t++)
global_mean[d] += x[t][d];
global_mean[d] /= T;
}
/* calculate global diagonal covariance */
for (d = 0; d < L; d++)
{
for (e = 0; e < L; e++)
model->cov[d][e] = 0;
for (t = 0; t < T; t++)
model->cov[d][d] += (x[t][d] - global_mean[d]) * (x[t][d] - global_mean[d]);
model->cov[d][d] /= T-1;
}
/* set all means close to global mean */
for (i = 0; i < N; i++)
{
for (d = 0; d < L; d++)
{
/* add some random noise related to covariance */
/* ideally the random number would be Gaussian(0,1), as a hack we make it uniform on [-0.25,0.25] */
model->mu[i][d] = global_mean[d] + (0.5 * rand() / (double) RAND_MAX - 0.25) * sqrt(model->cov[d][d]);
}
}
/* random intial and transition probs */
s = 0;
for (i = 0; i < N; i++)
{
model->p0[i] = 1 + rand() / (double) RAND_MAX;
s += model->p0[i];
ss = 0;
for (j = 0; j < N; j++)
{
model->a[i][j] = 1 + rand() / (double) RAND_MAX;
ss += model->a[i][j];
}
for (j = 0; j < N; j++)
{
model->a[i][j] /= ss;
}
}
for (i = 0; i < N; i++)
model->p0[i] /= s;
free(global_mean);
return model;
}
void hmm_close(model_t* model)
{
int i;
for (i = 0; i < model->N; i++)
{
free(model->a[i]);
free(model->mu[i]);
}
free(model->a);
free(model->mu);
for (i = 0; i < model->L; i++)
free(model->cov[i]);
free(model->cov);
free(model);
}
void hmm_train(double** x, int T, model_t* model)
{
int i, t;
double loglik; /* overall log-likelihood at each iteration */
int N = model->N;
int L = model->L;
double* p0 = model->p0;
double** a = model->a;
double** mu = model->mu;
double** cov = model->cov;
/* allocate memory */
double** gamma = (double**) malloc(T*sizeof(double*));
double*** xi = (double***) malloc(T*sizeof(double**));
for (t = 0; t < T; t++)
{
gamma[t] = (double*) malloc(N*sizeof(double));
xi[t] = (double**) malloc(N*sizeof(double*));
for (i = 0; i < N; i++)
xi[t][i] = (double*) malloc(N*sizeof(double));
}
/* temporary memory */
double* gauss_y = (double*) malloc(L*sizeof(double));
double* gauss_z = (double*) malloc(L*sizeof(double));
/* obs probs P(j|{x}) */
double** b = (double**) malloc(T*sizeof(double*));
for (t = 0; t < T; t++)
b[t] = (double*) malloc(N*sizeof(double));
/* inverse covariance and its determinant */
double** icov = (double**) malloc(L*sizeof(double*));
for (i = 0; i < L; i++)
icov[i] = (double*) malloc(L*sizeof(double));
double detcov;
double thresh = 0.0001;
int niter = 50;
int iter = 0;
double loglik1, loglik2;
int foundnan = 0;
while (iter < niter && !foundnan && !(iter > 1 && (loglik - loglik1) < thresh * (loglik1 - loglik2)))
{
++iter;
/*
fprintf(stderr, "calculating obsprobs...\n");
fflush(stderr);
*/
/* precalculate obs probs */
invert(cov, L, icov, &detcov);
for (t = 0; t < T; t++)
{
//int allzero = 1;
for (i = 0; i < N; i++)
{
b[t][i] = exp(loggauss(x[t], L, mu[i], icov, detcov, gauss_y, gauss_z));
//if (b[t][i] != 0)
// allzero = 0;
}
/*
if (allzero)
{
printf("all the b[t][i] were zero for t = %d, correcting...\n", t);
for (i = 0; i < N; i++)
{
b[t][i] = 0.00001;
}
}
*/
}
/*
fprintf(stderr, "forwards-backwards...\n");
fflush(stderr);
*/
forward_backwards(xi, gamma, &loglik, &loglik1, &loglik2, iter, N, T, p0, a, b);
/*
fprintf(stderr, "iteration %d: loglik = %f\n", iter, loglik);
fprintf(stderr, "re-estimation...\n");
fflush(stderr);
*/
if (ISNAN(loglik)) {
foundnan = 1;
continue;
}
baum_welch(p0, a, mu, cov, N, T, L, x, xi, gamma);
/*
printf("a:\n");
for (i = 0; i < model->N; i++)
{
for (j = 0; j < model->N; j++)
printf("%f ", model->a[i][j]);
printf("\n");
}
printf("\n\n");
*/
//hmm_print(model);
}
/* deallocate memory */
for (t = 0; t < T; t++)
{
free(gamma[t]);
free(b[t]);
for (i = 0; i < N; i++)
free(xi[t][i]);
free(xi[t]);
}
free(gamma);
free(xi);
free(b);
for (i = 0; i < L; i++)
free(icov[i]);
free(icov);
free(gauss_y);
free(gauss_z);
}
void mlss_reestimate(double* p0, double** a, double** mu, double** cov, int N, int T, int L, int* q, double** x)
{
/* fit a single Gaussian to observations in each state */
/* calculate the mean observation in each state */
/* calculate the overall covariance */
/* count transitions */
/* estimate initial probs from transitions (???) */
}
void baum_welch(double* p0, double** a, double** mu, double** cov, int N, int T, int L, double** x, double*** xi, double** gamma)
{
int i, j, t;
double* sum_gamma = (double*) malloc(N*sizeof(double));
/* temporary memory */
double* u = (double*) malloc(L*L*sizeof(double));
double* yy = (double*) malloc(T*L*sizeof(double));
double* yy2 = (double*) malloc(T*L*sizeof(double));
/* re-estimate transition probs */
for (i = 0; i < N; i++)
{
sum_gamma[i] = 0;
for (t = 0; t < T-1; t++)
sum_gamma[i] += gamma[t][i];
}
for (i = 0; i < N; i++)
{
if (sum_gamma[i] == 0)
{
/* fprintf(stderr, "sum_gamma[%d] was zero...\n", i); */
}
//double s = 0;
for (j = 0; j < N; j++)
{
a[i][j] = 0;
if (sum_gamma[i] == 0.) continue;
for (t = 0; t < T-1; t++)
a[i][j] += xi[t][i][j];
//s += a[i][j];
a[i][j] /= sum_gamma[i];
}
/*
for (j = 0; j < N; j++)
{
a[i][j] /= s;
}
*/
}
/* NB: now we need to sum gamma over all t */
for (i = 0; i < N; i++)
sum_gamma[i] += gamma[T-1][i];
/* re-estimate initial probs */
for (i = 0; i < N; i++)
p0[i] = gamma[0][i];
/* re-estimate covariance */
int d, e;
double sum_sum_gamma = 0;
for (i = 0; i < N; i++)
sum_sum_gamma += sum_gamma[i];
/*
for (d = 0; d < L; d++)
{
for (e = d; e < L; e++)
{
cov[d][e] = 0;
for (t = 0; t < T; t++)
for (j = 0; j < N; j++)
cov[d][e] += gamma[t][j] * (x[t][d] - mu[j][d]) * (x[t][e] - mu[j][e]);
cov[d][e] /= sum_sum_gamma;
if (ISNAN(cov[d][e]))
{
printf("cov[%d][%d] was nan\n", d, e);
for (j = 0; j < N; j++)
for (i = 0; i < L; i++)
if (ISNAN(mu[j][i]))
printf("mu[%d][%d] was nan\n", j, i);
for (t = 0; t < T; t++)
for (j = 0; j < N; j++)
if (ISNAN(gamma[t][j]))
printf("gamma[%d][%d] was nan\n", t, j);
exit(-1);
}
}
}
for (d = 0; d < L; d++)
for (e = 0; e < d; e++)
cov[d][e] = cov[e][d];
*/
/* using BLAS */
for (d = 0; d < L; d++)
for (e = 0; e < L; e++)
cov[d][e] = 0;
for (j = 0; j < N; j++)
{
for (d = 0; d < L; d++)
for (t = 0; t < T; t++)
{
yy[d*T+t] = x[t][d] - mu[j][d];
yy2[d*T+t] = gamma[t][j] * (x[t][d] - mu[j][d]);
}
cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, L, L, T, 1.0, yy, T, yy2, T, 0, u, L);
for (e = 0; e < L; e++)
for (d = 0; d < L; d++)
cov[d][e] += u[e*L+d];
}
for (d = 0; d < L; d++)
for (e = 0; e < L; e++)
cov[d][e] /= T; /* sum_sum_gamma; */
//printf("sum_sum_gamma = %f\n", sum_sum_gamma); /* fine, = T IS THIS ALWAYS TRUE with pooled cov?? */
/* re-estimate means */
for (j = 0; j < N; j++)
{
for (d = 0; d < L; d++)
{
mu[j][d] = 0;
for (t = 0; t < T; t++)
mu[j][d] += gamma[t][j] * x[t][d];
mu[j][d] /= sum_gamma[j];
}
}
/* deallocate memory */
free(sum_gamma);
free(yy);
free(yy2);
free(u);
}
void forward_backwards(double*** xi, double** gamma, double* loglik, double* loglik1, double* loglik2, int iter, int N, int T, double* p0, double** a, double** b)
{
/* forwards-backwards with scaling */
int i, j, t;
double** alpha = (double**) malloc(T*sizeof(double*));
double** beta = (double**) malloc(T*sizeof(double*));
for (t = 0; t < T; t++)
{
alpha[t] = (double*) malloc(N*sizeof(double));
beta[t] = (double*) malloc(N*sizeof(double));
}
/* scaling coefficients */
double* c = (double*) malloc(T*sizeof(double));
/* calculate forward probs and scale coefficients */
c[0] = 0;
for (i = 0; i < N; i++)
{
alpha[0][i] = p0[i] * b[0][i];
c[0] += alpha[0][i];
//printf("p0[%d] = %f, b[0][%d] = %f\n", i, p0[i], i, b[0][i]);
}
c[0] = 1 / c[0];
for (i = 0; i < N; i++)
{
alpha[0][i] *= c[0];
//printf("alpha[0][%d] = %f\n", i, alpha[0][i]); /* OK agrees with Matlab */
}
*loglik1 = *loglik;
*loglik = -log(c[0]);
if (iter == 2)
*loglik2 = *loglik;
for (t = 1; t < T; t++)
{
c[t] = 0;
for (j = 0; j < N; j++)
{
alpha[t][j] = 0;
for (i = 0; i < N; i++)
alpha[t][j] += alpha[t-1][i] * a[i][j];
alpha[t][j] *= b[t][j];
c[t] += alpha[t][j];
}
/*
if (c[t] == 0)
{
printf("c[%d] = 0, going to blow up so exiting\n", t);
for (i = 0; i < N; i++)
if (b[t][i] == 0)
fprintf(stderr, "b[%d][%d] was zero\n", t, i);
fprintf(stderr, "x[t] was \n");
for (i = 0; i < L; i++)
fprintf(stderr, "%f ", x[t][i]);
fprintf(stderr, "\n\n");
exit(-1);
}
*/
c[t] = 1 / c[t];
for (j = 0; j < N; j++)
alpha[t][j] *= c[t];
//printf("c[%d] = %e\n", t, c[t]);
*loglik -= log(c[t]);
}
/* calculate backwards probs using same coefficients */
for (i = 0; i < N; i++)
beta[T-1][i] = 1;
t = T - 1;
while (1)
{
for (i = 0; i < N; i++)
beta[t][i] *= c[t];
if (t == 0)
break;
for (i = 0; i < N; i++)
{
beta[t-1][i] = 0;
for (j = 0; j < N; j++)
beta[t-1][i] += a[i][j] * b[t][j] * beta[t][j];
}
t--;
}
/*
printf("alpha:\n");
for (t = 0; t < T; t++)
{
for (i = 0; i < N; i++)
printf("%4.4e\t\t", alpha[t][i]);
printf("\n");
}
printf("\n\n");printf("beta:\n");
for (t = 0; t < T; t++)
{
for (i = 0; i < N; i++)
printf("%4.4e\t\t", beta[t][i]);
printf("\n");
}
printf("\n\n");
*/
/* calculate posterior probs */
double tot;
for (t = 0; t < T; t++)
{
tot = 0;
for (i = 0; i < N; i++)
{
gamma[t][i] = alpha[t][i] * beta[t][i];
tot += gamma[t][i];
}
for (i = 0; i < N; i++)
{
gamma[t][i] /= tot;
//printf("gamma[%d][%d] = %f\n", t, i, gamma[t][i]);
}
}
for (t = 0; t < T-1; t++)
{
tot = 0;
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
xi[t][i][j] = alpha[t][i] * a[i][j] * b[t+1][j] * beta[t+1][j];
tot += xi[t][i][j];
}
}
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
xi[t][i][j] /= tot;
}
/*
// CHECK - fine
// gamma[t][i] = \sum_j{xi[t][i][j]}
tot = 0;
for (j = 0; j < N; j++)
tot += xi[3][1][j];
printf("gamma[3][1] = %f, sum_j(xi[3][1][j]) = %f\n", gamma[3][1], tot);
*/
for (t = 0; t < T; t++)
{
free(alpha[t]);
free(beta[t]);
}
free(alpha);
free(beta);
free(c);
}
void viterbi_decode(double** x, int T, model_t* model, int* q)
{
int i, j, t;
double max;
int havemax;
int N = model->N;
int L = model->L;
double* p0 = model->p0;
double** a = model->a;
double** mu = model->mu;
double** cov = model->cov;
/* inverse covariance and its determinant */
double** icov = (double**) malloc(L*sizeof(double*));
for (i = 0; i < L; i++)
icov[i] = (double*) malloc(L*sizeof(double));
double detcov;
double** logb = (double**) malloc(T*sizeof(double*));
double** phi = (double**) malloc(T*sizeof(double*));
int** psi = (int**) malloc(T*sizeof(int*));
for (t = 0; t < T; t++)
{
logb[t] = (double*) malloc(N*sizeof(double));
phi[t] = (double*) malloc(N*sizeof(double));
psi[t] = (int*) malloc(N*sizeof(int));
}
/* temporary memory */
double* gauss_y = (double*) malloc(L*sizeof(double));
double* gauss_z = (double*) malloc(L*sizeof(double));
/* calculate observation logprobs */
invert(cov, L, icov, &detcov);
for (t = 0; t < T; t++)
for (i = 0; i < N; i++)
logb[t][i] = loggauss(x[t], L, mu[i], icov, detcov, gauss_y, gauss_z);
/* initialise */
for (i = 0; i < N; i++)
{
phi[0][i] = log(p0[i]) + logb[0][i];
psi[0][i] = 0;
}
for (t = 1; t < T; t++)
{
for (j = 0; j < N; j++)
{
max = -1000000;
havemax = 0;
psi[t][j] = 0;
for (i = 0; i < N; i++)
{
if (phi[t-1][i] + log(a[i][j]) > max || !havemax)
{
max = phi[t-1][i] + log(a[i][j]);
phi[t][j] = max + logb[t][j];
psi[t][j] = i;
havemax = 1;
}
}
}
}
/* find maximising state at time T-1 */
max = phi[T-1][0];
q[T-1] = 0;
for (i = 1; i < N; i++)
{
if (phi[T-1][i] > max)
{
max = phi[T-1][i];
q[T-1] = i;
}
}
/* track back */
t = T - 2;
while (t >= 0)
{
q[t] = psi[t+1][q[t+1]];
t--;
}
/* de-allocate memory */
for (i = 0; i < L; i++)
free(icov[i]);
free(icov);
for (t = 0; t < T; t++)
{
free(logb[t]);
free(phi[t]);
free(psi[t]);
}
free(logb);
free(phi);
free(psi);
free(gauss_y);
free(gauss_z);
}
/* invert matrix and calculate determinant using LAPACK */
void invert(double** cov, int L, double** icov, double* detcov)
{
/* copy square matrix into a vector in column-major order */
double* a = (double*) malloc(L*L*sizeof(double));
int i, j;
for(j=0; j < L; j++)
for (i=0; i < L; i++)
a[j*L+i] = cov[i][j];
int M = (int) L;
int* ipiv = (int *) malloc(L*L*sizeof(int));
int ret;
/* LU decomposition */
ret = dgetrf_(&M, &M, a, &M, ipiv, &ret); /* ret should be zero, negative if cov is singular */
if (ret < 0)
{
fprintf(stderr, "Covariance matrix was singular, couldn't invert\n");
exit(-1);
}
/* find determinant */
double det = 1;
for(i = 0; i < L; i++)
det *= a[i*L+i];
// TODO: get this to work!!! If detcov < 0 then cov is bad anyway...
/*
int sign = 1;
for (i = 0; i < L; i++)
if (ipiv[i] != i)
sign = -sign;
det *= sign;
*/
if (det < 0)
det = -det;
*detcov = det;
/* allocate required working storage */
#ifndef HAVE_ATLAS
int lwork = -1;
double lwbest = 0.0;
dgetri_(&M, a, &M, ipiv, &lwbest, &lwork, &ret);
lwork = (int) lwbest;
double* work = (double*) malloc(lwork*sizeof(double));
#endif
/* find inverse */
dgetri_(&M, a, &M, ipiv, work, &lwork, &ret);
for(j=0; j < L; j++)
for (i=0; i < L; i++)
icov[i][j] = a[j*L+i];
#ifndef HAVE_ATLAS
free(work);
#endif
free(a);
}
/* probability of multivariate Gaussian given mean, inverse and determinant of covariance */
double gauss(double* x, int L, double* mu, double** icov, double detcov, double* y, double* z)
{
int i, j;
double s = 0;
for (i = 0; i < L; i++)
y[i] = x[i] - mu[i];
for (i = 0; i < L; i++)
{
//z[i] = 0;
//for (j = 0; j < L; j++)
// z[i] += icov[i][j] * y[j];
z[i] = cblas_ddot(L, &icov[i][0], 1, y, 1);
}
s = cblas_ddot(L, z, 1, y, 1);
//for (i = 0; i < L; i++)
// s += z[i] * y[i];
return exp(-s/2.0) / (pow(2*PI, L/2.0) * sqrt(detcov));
}
/* log probability of multivariate Gaussian given mean, inverse and determinant of covariance */
double loggauss(double* x, int L, double* mu, double** icov, double detcov, double* y, double* z)
{
int i, j;
double s = 0;
double ret;
for (i = 0; i < L; i++)
y[i] = x[i] - mu[i];
for (i = 0; i < L; i++)
{
//z[i] = 0;
//for (j = 0; j < L; j++)
// z[i] += icov[i][j] * y[j];
z[i] = cblas_ddot(L, &icov[i][0], 1, y, 1);
}
s = cblas_ddot(L, z, 1, y, 1);
//for (i = 0; i < L; i++)
// s += z[i] * y[i];
ret = -0.5 * (s + L * log(2*PI) + log(detcov));
/*
// TEST
if (ISINF(ret) > 0)
printf("loggauss returning infinity\n");
if (ISINF(ret) < 0)
printf("loggauss returning -infinity\n");
if (ISNAN(ret))
printf("loggauss returning nan\n");
*/
return ret;
}
void hmm_print(model_t* model)
{
int i, j;
printf("p0:\n");
for (i = 0; i < model->N; i++)
printf("%f ", model->p0[i]);
printf("\n\n");
printf("a:\n");
for (i = 0; i < model->N; i++)
{
for (j = 0; j < model->N; j++)
printf("%f ", model->a[i][j]);
printf("\n");
}
printf("\n\n");
printf("mu:\n");
for (i = 0; i < model->N; i++)
{
for (j = 0; j < model->L; j++)
printf("%f ", model->mu[i][j]);
printf("\n");
}
printf("\n\n");
printf("cov:\n");
for (i = 0; i < model->L; i++)
{
for (j = 0; j < model->L; j++)
printf("%f ", model->cov[i][j]);
printf("\n");
}
printf("\n\n");
}

52
libs/qm-dsp/hmm/hmm.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef _HMM_H
#define _HMM_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* hmm.h
*
* Created by Mark Levy on 12/02/2006.
* Copyright 2006 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 PI
#define PI 3.14159265358979323846264338327950288
#endif
typedef struct _model_t {
int N; /* number of states */
double* p0; /* initial probs */
double** a; /* transition probs */
int L; /* dimensionality of data */
double** mu; /* state means */
double** cov; /* covariance, tied between all states */
} model_t;
void hmm_train(double** x, int T, model_t* model); /* with scaling */
void forward_backwards(double*** xi, double** gamma, double* loglik, double* loglik1, double* loglik2, int iter,
int N, int T, double* p0, double** a, double** b);
void baum_welch(double* p0, double** a, double** mu, double** cov, int N, int T, int L, double** x, double*** xi, double** gamma);
void viterbi_decode(double** x, int T, model_t* model, int* q); /* using logs */
model_t* hmm_init(double** x, int T, int L, int N);
void hmm_close(model_t* model);
void invert(double** cov, int L, double** icov, double* detcov); /* uses LAPACK (included with Mac OSX) */
double gauss(double* x, int L, double* mu, double** icov, double detcov, double* y, double* z);
double loggauss(double* x, int L, double* mu, double** icov, double detcov, double* y, double* z);
void hmm_print(model_t* model);
#ifdef __cplusplus
}
#endif
#endif

578
libs/qm-dsp/include/cblas.h Normal file
View File

@ -0,0 +1,578 @@
#ifndef CBLAS_H
#define CBLAS_H
#include <stddef.h>
/* Allow the use in C++ code. */
#ifdef __cplusplus
extern "C"
{
#endif
/*
* Enumerated and derived types
*/
#define CBLAS_INDEX size_t /* this may vary between platforms */
enum CBLAS_ORDER {CblasRowMajor=101, CblasColMajor=102};
enum CBLAS_TRANSPOSE {CblasNoTrans=111, CblasTrans=112, CblasConjTrans=113};
enum CBLAS_UPLO {CblasUpper=121, CblasLower=122};
enum CBLAS_DIAG {CblasNonUnit=131, CblasUnit=132};
enum CBLAS_SIDE {CblasLeft=141, CblasRight=142};
/*
* ===========================================================================
* Prototypes for level 1 BLAS functions (complex are recast as routines)
* ===========================================================================
*/
float cblas_sdsdot(const int N, const float alpha, const float *X,
const int incX, const float *Y, const int incY);
double cblas_dsdot(const int N, const float *X, const int incX, const float *Y,
const int incY);
float cblas_sdot(const int N, const float *X, const int incX,
const float *Y, const int incY);
double cblas_ddot(const int N, const double *X, const int incX,
const double *Y, const int incY);
/*
* Functions having prefixes Z and C only
*/
void cblas_cdotu_sub(const int N, const void *X, const int incX,
const void *Y, const int incY, void *dotu);
void cblas_cdotc_sub(const int N, const void *X, const int incX,
const void *Y, const int incY, void *dotc);
void cblas_zdotu_sub(const int N, const void *X, const int incX,
const void *Y, const int incY, void *dotu);
void cblas_zdotc_sub(const int N, const void *X, const int incX,
const void *Y, const int incY, void *dotc);
/*
* Functions having prefixes S D SC DZ
*/
float cblas_snrm2(const int N, const float *X, const int incX);
float cblas_sasum(const int N, const float *X, const int incX);
double cblas_dnrm2(const int N, const double *X, const int incX);
double cblas_dasum(const int N, const double *X, const int incX);
float cblas_scnrm2(const int N, const void *X, const int incX);
float cblas_scasum(const int N, const void *X, const int incX);
double cblas_dznrm2(const int N, const void *X, const int incX);
double cblas_dzasum(const int N, const void *X, const int incX);
/*
* Functions having standard 4 prefixes (S D C Z)
*/
CBLAS_INDEX cblas_isamax(const int N, const float *X, const int incX);
CBLAS_INDEX cblas_idamax(const int N, const double *X, const int incX);
CBLAS_INDEX cblas_icamax(const int N, const void *X, const int incX);
CBLAS_INDEX cblas_izamax(const int N, const void *X, const int incX);
/*
* ===========================================================================
* Prototypes for level 1 BLAS routines
* ===========================================================================
*/
/*
* Routines with standard 4 prefixes (s, d, c, z)
*/
void cblas_sswap(const int N, float *X, const int incX,
float *Y, const int incY);
void cblas_scopy(const int N, const float *X, const int incX,
float *Y, const int incY);
void cblas_saxpy(const int N, const float alpha, const float *X,
const int incX, float *Y, const int incY);
void cblas_dswap(const int N, double *X, const int incX,
double *Y, const int incY);
void cblas_dcopy(const int N, const double *X, const int incX,
double *Y, const int incY);
void cblas_daxpy(const int N, const double alpha, const double *X,
const int incX, double *Y, const int incY);
void cblas_cswap(const int N, void *X, const int incX,
void *Y, const int incY);
void cblas_ccopy(const int N, const void *X, const int incX,
void *Y, const int incY);
void cblas_caxpy(const int N, const void *alpha, const void *X,
const int incX, void *Y, const int incY);
void cblas_zswap(const int N, void *X, const int incX,
void *Y, const int incY);
void cblas_zcopy(const int N, const void *X, const int incX,
void *Y, const int incY);
void cblas_zaxpy(const int N, const void *alpha, const void *X,
const int incX, void *Y, const int incY);
/*
* Routines with S and D prefix only
*/
void cblas_srotg(float *a, float *b, float *c, float *s);
void cblas_srotmg(float *d1, float *d2, float *b1, const float b2, float *P);
void cblas_srot(const int N, float *X, const int incX,
float *Y, const int incY, const float c, const float s);
void cblas_srotm(const int N, float *X, const int incX,
float *Y, const int incY, const float *P);
void cblas_drotg(double *a, double *b, double *c, double *s);
void cblas_drotmg(double *d1, double *d2, double *b1, const double b2, double *P);
void cblas_drot(const int N, double *X, const int incX,
double *Y, const int incY, const double c, const double s);
void cblas_drotm(const int N, double *X, const int incX,
double *Y, const int incY, const double *P);
/*
* Routines with S D C Z CS and ZD prefixes
*/
void cblas_sscal(const int N, const float alpha, float *X, const int incX);
void cblas_dscal(const int N, const double alpha, double *X, const int incX);
void cblas_cscal(const int N, const void *alpha, void *X, const int incX);
void cblas_zscal(const int N, const void *alpha, void *X, const int incX);
void cblas_csscal(const int N, const float alpha, void *X, const int incX);
void cblas_zdscal(const int N, const double alpha, void *X, const int incX);
/*
* ===========================================================================
* Prototypes for level 2 BLAS
* ===========================================================================
*/
/*
* Routines with standard 4 prefixes (S, D, C, Z)
*/
void cblas_sgemv(const enum CBLAS_ORDER order,
const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
const float alpha, const float *A, const int lda,
const float *X, const int incX, const float beta,
float *Y, const int incY);
void cblas_sgbmv(const enum CBLAS_ORDER order,
const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
const int KL, const int KU, const float alpha,
const float *A, const int lda, const float *X,
const int incX, const float beta, float *Y, const int incY);
void cblas_strmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const float *A, const int lda,
float *X, const int incX);
void cblas_stbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const int K, const float *A, const int lda,
float *X, const int incX);
void cblas_stpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const float *Ap, float *X, const int incX);
void cblas_strsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const float *A, const int lda, float *X,
const int incX);
void cblas_stbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const int K, const float *A, const int lda,
float *X, const int incX);
void cblas_stpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const float *Ap, float *X, const int incX);
void cblas_dgemv(const enum CBLAS_ORDER order,
const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
const double alpha, const double *A, const int lda,
const double *X, const int incX, const double beta,
double *Y, const int incY);
void cblas_dgbmv(const enum CBLAS_ORDER order,
const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
const int KL, const int KU, const double alpha,
const double *A, const int lda, const double *X,
const int incX, const double beta, double *Y, const int incY);
void cblas_dtrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const double *A, const int lda,
double *X, const int incX);
void cblas_dtbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const int K, const double *A, const int lda,
double *X, const int incX);
void cblas_dtpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const double *Ap, double *X, const int incX);
void cblas_dtrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const double *A, const int lda, double *X,
const int incX);
void cblas_dtbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const int K, const double *A, const int lda,
double *X, const int incX);
void cblas_dtpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const double *Ap, double *X, const int incX);
void cblas_cgemv(const enum CBLAS_ORDER order,
const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
const void *alpha, const void *A, const int lda,
const void *X, const int incX, const void *beta,
void *Y, const int incY);
void cblas_cgbmv(const enum CBLAS_ORDER order,
const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
const int KL, const int KU, const void *alpha,
const void *A, const int lda, const void *X,
const int incX, const void *beta, void *Y, const int incY);
void cblas_ctrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const void *A, const int lda,
void *X, const int incX);
void cblas_ctbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const int K, const void *A, const int lda,
void *X, const int incX);
void cblas_ctpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const void *Ap, void *X, const int incX);
void cblas_ctrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const void *A, const int lda, void *X,
const int incX);
void cblas_ctbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const int K, const void *A, const int lda,
void *X, const int incX);
void cblas_ctpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const void *Ap, void *X, const int incX);
void cblas_zgemv(const enum CBLAS_ORDER order,
const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
const void *alpha, const void *A, const int lda,
const void *X, const int incX, const void *beta,
void *Y, const int incY);
void cblas_zgbmv(const enum CBLAS_ORDER order,
const enum CBLAS_TRANSPOSE TransA, const int M, const int N,
const int KL, const int KU, const void *alpha,
const void *A, const int lda, const void *X,
const int incX, const void *beta, void *Y, const int incY);
void cblas_ztrmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const void *A, const int lda,
void *X, const int incX);
void cblas_ztbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const int K, const void *A, const int lda,
void *X, const int incX);
void cblas_ztpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const void *Ap, void *X, const int incX);
void cblas_ztrsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const void *A, const int lda, void *X,
const int incX);
void cblas_ztbsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const int K, const void *A, const int lda,
void *X, const int incX);
void cblas_ztpsv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE TransA, const enum CBLAS_DIAG Diag,
const int N, const void *Ap, void *X, const int incX);
/*
* Routines with S and D prefixes only
*/
void cblas_ssymv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const float alpha, const float *A,
const int lda, const float *X, const int incX,
const float beta, float *Y, const int incY);
void cblas_ssbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const int K, const float alpha, const float *A,
const int lda, const float *X, const int incX,
const float beta, float *Y, const int incY);
void cblas_sspmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const float alpha, const float *Ap,
const float *X, const int incX,
const float beta, float *Y, const int incY);
void cblas_sger(const enum CBLAS_ORDER order, const int M, const int N,
const float alpha, const float *X, const int incX,
const float *Y, const int incY, float *A, const int lda);
void cblas_ssyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const float alpha, const float *X,
const int incX, float *A, const int lda);
void cblas_sspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const float alpha, const float *X,
const int incX, float *Ap);
void cblas_ssyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const float alpha, const float *X,
const int incX, const float *Y, const int incY, float *A,
const int lda);
void cblas_sspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const float alpha, const float *X,
const int incX, const float *Y, const int incY, float *A);
void cblas_dsymv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const double alpha, const double *A,
const int lda, const double *X, const int incX,
const double beta, double *Y, const int incY);
void cblas_dsbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const int K, const double alpha, const double *A,
const int lda, const double *X, const int incX,
const double beta, double *Y, const int incY);
void cblas_dspmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const double alpha, const double *Ap,
const double *X, const int incX,
const double beta, double *Y, const int incY);
void cblas_dger(const enum CBLAS_ORDER order, const int M, const int N,
const double alpha, const double *X, const int incX,
const double *Y, const int incY, double *A, const int lda);
void cblas_dsyr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const double alpha, const double *X,
const int incX, double *A, const int lda);
void cblas_dspr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const double alpha, const double *X,
const int incX, double *Ap);
void cblas_dsyr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const double alpha, const double *X,
const int incX, const double *Y, const int incY, double *A,
const int lda);
void cblas_dspr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const double alpha, const double *X,
const int incX, const double *Y, const int incY, double *A);
/*
* Routines with C and Z prefixes only
*/
void cblas_chemv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const void *alpha, const void *A,
const int lda, const void *X, const int incX,
const void *beta, void *Y, const int incY);
void cblas_chbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const int K, const void *alpha, const void *A,
const int lda, const void *X, const int incX,
const void *beta, void *Y, const int incY);
void cblas_chpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const void *alpha, const void *Ap,
const void *X, const int incX,
const void *beta, void *Y, const int incY);
void cblas_cgeru(const enum CBLAS_ORDER order, const int M, const int N,
const void *alpha, const void *X, const int incX,
const void *Y, const int incY, void *A, const int lda);
void cblas_cgerc(const enum CBLAS_ORDER order, const int M, const int N,
const void *alpha, const void *X, const int incX,
const void *Y, const int incY, void *A, const int lda);
void cblas_cher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const float alpha, const void *X, const int incX,
void *A, const int lda);
void cblas_chpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const float alpha, const void *X,
const int incX, void *A);
void cblas_cher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N,
const void *alpha, const void *X, const int incX,
const void *Y, const int incY, void *A, const int lda);
void cblas_chpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N,
const void *alpha, const void *X, const int incX,
const void *Y, const int incY, void *Ap);
void cblas_zhemv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const void *alpha, const void *A,
const int lda, const void *X, const int incX,
const void *beta, void *Y, const int incY);
void cblas_zhbmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const int K, const void *alpha, const void *A,
const int lda, const void *X, const int incX,
const void *beta, void *Y, const int incY);
void cblas_zhpmv(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const void *alpha, const void *Ap,
const void *X, const int incX,
const void *beta, void *Y, const int incY);
void cblas_zgeru(const enum CBLAS_ORDER order, const int M, const int N,
const void *alpha, const void *X, const int incX,
const void *Y, const int incY, void *A, const int lda);
void cblas_zgerc(const enum CBLAS_ORDER order, const int M, const int N,
const void *alpha, const void *X, const int incX,
const void *Y, const int incY, void *A, const int lda);
void cblas_zher(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const double alpha, const void *X, const int incX,
void *A, const int lda);
void cblas_zhpr(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo,
const int N, const double alpha, const void *X,
const int incX, void *A);
void cblas_zher2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N,
const void *alpha, const void *X, const int incX,
const void *Y, const int incY, void *A, const int lda);
void cblas_zhpr2(const enum CBLAS_ORDER order, const enum CBLAS_UPLO Uplo, const int N,
const void *alpha, const void *X, const int incX,
const void *Y, const int incY, void *Ap);
/*
* ===========================================================================
* Prototypes for level 3 BLAS
* ===========================================================================
*/
/*
* Routines with standard 4 prefixes (S, D, C, Z)
*/
void cblas_sgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
const int K, const float alpha, const float *A,
const int lda, const float *B, const int ldb,
const float beta, float *C, const int ldc);
void cblas_ssymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const int M, const int N,
const float alpha, const float *A, const int lda,
const float *B, const int ldb, const float beta,
float *C, const int ldc);
void cblas_ssyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
const float alpha, const float *A, const int lda,
const float beta, float *C, const int ldc);
void cblas_ssyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
const float alpha, const float *A, const int lda,
const float *B, const int ldb, const float beta,
float *C, const int ldc);
void cblas_strmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_DIAG Diag, const int M, const int N,
const float alpha, const float *A, const int lda,
float *B, const int ldb);
void cblas_strsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_DIAG Diag, const int M, const int N,
const float alpha, const float *A, const int lda,
float *B, const int ldb);
void cblas_dgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
const int K, const double alpha, const double *A,
const int lda, const double *B, const int ldb,
const double beta, double *C, const int ldc);
void cblas_dsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const int M, const int N,
const double alpha, const double *A, const int lda,
const double *B, const int ldb, const double beta,
double *C, const int ldc);
void cblas_dsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
const double alpha, const double *A, const int lda,
const double beta, double *C, const int ldc);
void cblas_dsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
const double alpha, const double *A, const int lda,
const double *B, const int ldb, const double beta,
double *C, const int ldc);
void cblas_dtrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_DIAG Diag, const int M, const int N,
const double alpha, const double *A, const int lda,
double *B, const int ldb);
void cblas_dtrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_DIAG Diag, const int M, const int N,
const double alpha, const double *A, const int lda,
double *B, const int ldb);
void cblas_cgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
const int K, const void *alpha, const void *A,
const int lda, const void *B, const int ldb,
const void *beta, void *C, const int ldc);
void cblas_csymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const int M, const int N,
const void *alpha, const void *A, const int lda,
const void *B, const int ldb, const void *beta,
void *C, const int ldc);
void cblas_csyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
const void *alpha, const void *A, const int lda,
const void *beta, void *C, const int ldc);
void cblas_csyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
const void *alpha, const void *A, const int lda,
const void *B, const int ldb, const void *beta,
void *C, const int ldc);
void cblas_ctrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_DIAG Diag, const int M, const int N,
const void *alpha, const void *A, const int lda,
void *B, const int ldb);
void cblas_ctrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_DIAG Diag, const int M, const int N,
const void *alpha, const void *A, const int lda,
void *B, const int ldb);
void cblas_zgemm(const enum CBLAS_ORDER Order, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_TRANSPOSE TransB, const int M, const int N,
const int K, const void *alpha, const void *A,
const int lda, const void *B, const int ldb,
const void *beta, void *C, const int ldc);
void cblas_zsymm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const int M, const int N,
const void *alpha, const void *A, const int lda,
const void *B, const int ldb, const void *beta,
void *C, const int ldc);
void cblas_zsyrk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
const void *alpha, const void *A, const int lda,
const void *beta, void *C, const int ldc);
void cblas_zsyr2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
const void *alpha, const void *A, const int lda,
const void *B, const int ldb, const void *beta,
void *C, const int ldc);
void cblas_ztrmm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_DIAG Diag, const int M, const int N,
const void *alpha, const void *A, const int lda,
void *B, const int ldb);
void cblas_ztrsm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const enum CBLAS_TRANSPOSE TransA,
const enum CBLAS_DIAG Diag, const int M, const int N,
const void *alpha, const void *A, const int lda,
void *B, const int ldb);
/*
* Routines with prefixes C and Z only
*/
void cblas_chemm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const int M, const int N,
const void *alpha, const void *A, const int lda,
const void *B, const int ldb, const void *beta,
void *C, const int ldc);
void cblas_cherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
const float alpha, const void *A, const int lda,
const float beta, void *C, const int ldc);
void cblas_cher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
const void *alpha, const void *A, const int lda,
const void *B, const int ldb, const float beta,
void *C, const int ldc);
void cblas_zhemm(const enum CBLAS_ORDER Order, const enum CBLAS_SIDE Side,
const enum CBLAS_UPLO Uplo, const int M, const int N,
const void *alpha, const void *A, const int lda,
const void *B, const int ldb, const void *beta,
void *C, const int ldc);
void cblas_zherk(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
const double alpha, const void *A, const int lda,
const double beta, void *C, const int ldc);
void cblas_zher2k(const enum CBLAS_ORDER Order, const enum CBLAS_UPLO Uplo,
const enum CBLAS_TRANSPOSE Trans, const int N, const int K,
const void *alpha, const void *A, const int lda,
const void *B, const int ldb, const double beta,
void *C, const int ldc);
void cblas_xerbla(int p, const char *rout, const char *form, ...);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,56 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 "Correlation.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Correlation::Correlation()
{
}
Correlation::~Correlation()
{
}
void Correlation::doAutoUnBiased(double *src, double *dst, unsigned int length)
{
double tmp = 0.0;
double outVal = 0.0;
unsigned int i,j;
for( i = 0; i < length; i++)
{
for( j = i; j < length; j++)
{
tmp += src[ j-i ] * src[ j ];
}
outVal = tmp / ( length - i );
if( outVal <= 0 )
dst[ i ] = EPS;
else
dst[ i ] = outVal;
tmp = 0.0;
}
}

View File

@ -0,0 +1,30 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 CORRELATION_H
#define CORRELATION_H
#define EPS 2.2204e-016
class Correlation
{
public:
void doAutoUnBiased( double* src, double* dst, unsigned int length );
Correlation();
virtual ~Correlation();
};
#endif //

View File

@ -0,0 +1,47 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2008 Kurt Jacobson.
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 "CosineDistance.h"
#include <iostream>
#include <limits>
using std::cerr;
double CosineDistance::distance(const vector<double> &v1,
const vector<double> &v2)
{
dist = 1.0; dDenTot = 0; dDen1 = 0; dDen2 = 0; dSum1 =0;
double small = 1e-20;
//check if v1, v2 same size
if (v1.size() != v2.size())
{
cerr << "CosineDistance::distance: ERROR: vectors not the same size\n";
return 1.0;
}
else
{
for(int i=0; i<v1.size(); i++)
{
dSum1 += v1[i]*v2[i];
dDen1 += v1[i]*v1[i];
dDen2 += v2[i]*v2[i];
}
dDenTot = sqrt(fabs(dDen1*dDen2)) + small;
dist = 1-((dSum1)/dDenTot);
return dist;
}
}

View File

@ -0,0 +1,37 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2008 Kurt Jacobson.
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 COSINEDISTANCE_H
#define COSINEDISTANCE_H
#include <vector>
#include <math.h>
using std::vector;
class CosineDistance
{
public:
CosineDistance() { }
~CosineDistance() { }
double distance(const vector<double> &v1, const vector<double> &v2);
protected:
double dist, dDenTot, dDen1, dDen2, dSum1;
};
#endif

View File

@ -0,0 +1,64 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2008 QMUL
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 "KLDivergence.h"
#include <cmath>
double KLDivergence::distanceGaussian(const vector<double> &m1,
const vector<double> &v1,
const vector<double> &m2,
const vector<double> &v2)
{
int sz = m1.size();
double d = -2.0 * sz;
double small = 1e-20;
for (int k = 0; k < sz; ++k) {
double kv1 = v1[k] + small;
double kv2 = v2[k] + small;
double km = (m1[k] - m2[k]) + small;
d += kv1 / kv2 + kv2 / kv1;
d += km * (1.0 / kv1 + 1.0 / kv2) * km;
}
d /= 2.0;
return d;
}
double KLDivergence::distanceDistribution(const vector<double> &d1,
const vector<double> &d2,
bool symmetrised)
{
int sz = d1.size();
double d = 0;
double small = 1e-20;
for (int i = 0; i < sz; ++i) {
d += d1[i] * log10((d1[i] + small) / (d2[i] + small));
}
if (symmetrised) {
d += distanceDistribution(d2, d1, false);
}
return d;
}

View File

@ -0,0 +1,54 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright 2008 QMUL.
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 KLDIVERGENCE_H
#define KLDIVERGENCE_H
#include <vector>
using std::vector;
/**
* Helper methods for calculating Kullback-Leibler divergences.
*/
class KLDivergence
{
public:
KLDivergence() { }
~KLDivergence() { }
/**
* Calculate a symmetrised Kullback-Leibler divergence of Gaussian
* models based on mean and variance vectors. All input vectors
* must be of equal size.
*/
double distanceGaussian(const vector<double> &means1,
const vector<double> &variances1,
const vector<double> &means2,
const vector<double> &variances2);
/**
* Calculate a Kullback-Leibler divergence of two probability
* distributions. Input vectors must be of equal size. If
* symmetrised is true, the result will be the symmetrised
* distance (equal to KL(d1, d2) + KL(d2, d1)).
*/
double distanceDistribution(const vector<double> &d1,
const vector<double> &d2,
bool symmetrised);
};
#endif

View File

@ -0,0 +1,60 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 MATHALIASES_H
#define MATHALIASES_H
#include <cmath>
#include <complex>
using namespace std;
typedef complex<double> ComplexData;
#ifndef PI
#define PI (3.14159265358979232846)
#endif
#define TWO_PI (2. * PI)
#define EPS 2.2204e-016
/* aliases to math.h functions */
#define EXP exp
#define COS cos
#define SIN sin
#define ABS fabs
#define POW powf
#define SQRT sqrtf
#define LOG10 log10f
#define LOG logf
#define FLOOR floorf
#define TRUNC truncf
/* aliases to complex.h functions */
/** sample = EXPC(complex) */
#define EXPC cexpf
/** complex = CEXPC(complex) */
#define CEXPC cexp
/** sample = ARGC(complex) */
#define ARGC cargf
/** sample = ABSC(complex) norm */
#define ABSC cabsf
/** sample = REAL(complex) */
#define REAL crealf
/** sample = IMAG(complex) */
#define IMAG cimagf
#endif

View File

@ -0,0 +1,401 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 "MathUtilities.h"
#include <iostream>
#include <cmath>
double MathUtilities::mod(double x, double y)
{
double a = floor( x / y );
double b = x - ( y * a );
return b;
}
double MathUtilities::princarg(double ang)
{
double ValOut;
ValOut = mod( ang + M_PI, -2 * M_PI ) + M_PI;
return ValOut;
}
void MathUtilities::getAlphaNorm(const double *data, unsigned int len, unsigned int alpha, double* ANorm)
{
unsigned int i;
double temp = 0.0;
double a=0.0;
for( i = 0; i < len; i++)
{
temp = data[ i ];
a += ::pow( fabs(temp), double(alpha) );
}
a /= ( double )len;
a = ::pow( a, ( 1.0 / (double) alpha ) );
*ANorm = a;
}
double MathUtilities::getAlphaNorm( const std::vector <double> &data, unsigned int alpha )
{
unsigned int i;
unsigned int len = data.size();
double temp = 0.0;
double a=0.0;
for( i = 0; i < len; i++)
{
temp = data[ i ];
a += ::pow( fabs(temp), double(alpha) );
}
a /= ( double )len;
a = ::pow( a, ( 1.0 / (double) alpha ) );
return a;
}
double MathUtilities::round(double x)
{
double val = (double)floor(x + 0.5);
return val;
}
double MathUtilities::median(const double *src, unsigned int len)
{
unsigned int i, j;
double tmp = 0.0;
double tempMedian;
double medianVal;
double* scratch = new double[ len ];//Vector < double > sortedX = Vector < double > ( size );
for ( i = 0; i < len; i++ )
{
scratch[i] = src[i];
}
for ( i = 0; i < len - 1; i++ )
{
for ( j = 0; j < len - 1 - i; j++ )
{
if ( scratch[j + 1] < scratch[j] )
{
// compare the two neighbors
tmp = scratch[j]; // swap a[j] and a[j+1]
scratch[j] = scratch[j + 1];
scratch[j + 1] = tmp;
}
}
}
int middle;
if ( len % 2 == 0 )
{
middle = len / 2;
tempMedian = ( scratch[middle] + scratch[middle - 1] ) / 2;
}
else
{
middle = ( int )floor( len / 2.0 );
tempMedian = scratch[middle];
}
medianVal = tempMedian;
delete [] scratch;
return medianVal;
}
double MathUtilities::sum(const double *src, unsigned int len)
{
unsigned int i ;
double retVal =0.0;
for( i = 0; i < len; i++)
{
retVal += src[ i ];
}
return retVal;
}
double MathUtilities::mean(const double *src, unsigned int len)
{
double retVal =0.0;
double s = sum( src, len );
retVal = s / (double)len;
return retVal;
}
double MathUtilities::mean(const std::vector<double> &src,
unsigned int start,
unsigned int count)
{
double sum = 0.;
for (int i = 0; i < count; ++i)
{
sum += src[start + i];
}
return sum / count;
}
void MathUtilities::getFrameMinMax(const double *data, unsigned int len, double *min, double *max)
{
unsigned int i;
double temp = 0.0;
double a=0.0;
if (len == 0) {
*min = *max = 0;
return;
}
*min = data[0];
*max = data[0];
for( i = 0; i < len; i++)
{
temp = data[ i ];
if( temp < *min )
{
*min = temp ;
}
if( temp > *max )
{
*max = temp ;
}
}
}
int MathUtilities::getMax( double* pData, unsigned int Length, double* pMax )
{
unsigned int index = 0;
unsigned int i;
double temp = 0.0;
double max = pData[0];
for( i = 0; i < Length; i++)
{
temp = pData[ i ];
if( temp > max )
{
max = temp ;
index = i;
}
}
if (pMax) *pMax = max;
return index;
}
int MathUtilities::getMax( const std::vector<double> & data, double* pMax )
{
unsigned int index = 0;
unsigned int i;
double temp = 0.0;
double max = data[0];
for( i = 0; i < data.size(); i++)
{
temp = data[ i ];
if( temp > max )
{
max = temp ;
index = i;
}
}
if (pMax) *pMax = max;
return index;
}
void MathUtilities::circShift( double* pData, int length, int shift)
{
shift = shift % length;
double temp;
int i,n;
for( i = 0; i < shift; i++)
{
temp=*(pData + length - 1);
for( n = length-2; n >= 0; n--)
{
*(pData+n+1)=*(pData+n);
}
*pData = temp;
}
}
int MathUtilities::compareInt (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
void MathUtilities::normalise(double *data, int length, NormaliseType type)
{
switch (type) {
case NormaliseNone: return;
case NormaliseUnitSum:
{
double sum = 0.0;
for (int i = 0; i < length; ++i) {
sum += data[i];
}
if (sum != 0.0) {
for (int i = 0; i < length; ++i) {
data[i] /= sum;
}
}
}
break;
case NormaliseUnitMax:
{
double max = 0.0;
for (int i = 0; i < length; ++i) {
if (fabs(data[i]) > max) {
max = fabs(data[i]);
}
}
if (max != 0.0) {
for (int i = 0; i < length; ++i) {
data[i] /= max;
}
}
}
break;
}
}
void MathUtilities::normalise(std::vector<double> &data, NormaliseType type)
{
switch (type) {
case NormaliseNone: return;
case NormaliseUnitSum:
{
double sum = 0.0;
for (int i = 0; i < data.size(); ++i) sum += data[i];
if (sum != 0.0) {
for (int i = 0; i < data.size(); ++i) data[i] /= sum;
}
}
break;
case NormaliseUnitMax:
{
double max = 0.0;
for (int i = 0; i < data.size(); ++i) {
if (fabs(data[i]) > max) max = fabs(data[i]);
}
if (max != 0.0) {
for (int i = 0; i < data.size(); ++i) data[i] /= max;
}
}
break;
}
}
void MathUtilities::adaptiveThreshold(std::vector<double> &data)
{
int sz = int(data.size());
if (sz == 0) return;
std::vector<double> smoothed(sz);
int p_pre = 8;
int p_post = 7;
for (int i = 0; i < sz; ++i) {
int first = std::max(0, i - p_pre);
int last = std::min(sz - 1, i + p_post);
smoothed[i] = mean(data, first, last - first + 1);
}
for (int i = 0; i < sz; i++) {
data[i] -= smoothed[i];
if (data[i] < 0.0) data[i] = 0.0;
}
}
bool
MathUtilities::isPowerOfTwo(int x)
{
if (x < 2) return false;
if (x & (x-1)) return false;
return true;
}
int
MathUtilities::nextPowerOfTwo(int x)
{
if (isPowerOfTwo(x)) return x;
int n = 1;
while (x) { x >>= 1; n <<= 1; }
return n;
}
int
MathUtilities::previousPowerOfTwo(int x)
{
if (isPowerOfTwo(x)) return x;
int n = 1;
x >>= 1;
while (x) { x >>= 1; n <<= 1; }
return n;
}
int
MathUtilities::nearestPowerOfTwo(int x)
{
if (isPowerOfTwo(x)) return x;
int n0 = previousPowerOfTwo(x), n1 = nearestPowerOfTwo(x);
if (x - n0 < n1 - x) return n0;
else return n1;
}

View File

@ -0,0 +1,69 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file 2005-2006 Christian Landone.
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 MATHUTILITIES_H
#define MATHUTILITIES_H
#include <vector>
#include "nan-inf.h"
class MathUtilities
{
public:
static double round( double x );
static void getFrameMinMax( const double* data, unsigned int len, double* min, double* max );
static double mean( const double* src, unsigned int len );
static double mean( const std::vector<double> &data,
unsigned int start, unsigned int count );
static double sum( const double* src, unsigned int len );
static double median( const double* src, unsigned int len );
static double princarg( double ang );
static double mod( double x, double y);
static void getAlphaNorm(const double *data, unsigned int len, unsigned int alpha, double* ANorm);
static double getAlphaNorm(const std::vector <double> &data, unsigned int alpha );
static void circShift( double* data, int length, int shift);
static int getMax( double* data, unsigned int length, double* max = 0 );
static int getMax( const std::vector<double> &data, double* max = 0 );
static int compareInt(const void * a, const void * b);
enum NormaliseType {
NormaliseNone,
NormaliseUnitSum,
NormaliseUnitMax
};
static void normalise(double *data, int length,
NormaliseType n = NormaliseUnitMax);
static void normalise(std::vector<double> &data,
NormaliseType n = NormaliseUnitMax);
// moving mean threshholding:
static void adaptiveThreshold(std::vector<double> &data);
static bool isPowerOfTwo(int x);
static int nextPowerOfTwo(int x); // e.g. 1300 -> 2048, 2048 -> 2048
static int previousPowerOfTwo(int x); // e.g. 1300 -> 1024, 2048 -> 2048
static int nearestPowerOfTwo(int x); // e.g. 1300 -> 1024, 1700 -> 2048
};
#endif

407
libs/qm-dsp/maths/Polyfit.h Normal file
View File

@ -0,0 +1,407 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
//---------------------------------------------------------------------------
#ifndef PolyfitHPP
#define PolyfitHPP
//---------------------------------------------------------------------------
// Least-squares curve fitting class for arbitrary data types
/*
{ ******************************************
**** Scientific Subroutine Library ****
**** for C++ Builder ****
******************************************
The following programs were written by Allen Miller and appear in the
book entitled "Pascal Programs For Scientists And Engineers" which is
published by Sybex, 1981.
They were originally typed and submitted to MTPUG in Oct. 1982
Juergen Loewner
Hoher Heckenweg 3
D-4400 Muenster
They have had minor corrections and adaptations for Turbo Pascal by
Jeff Weiss
1572 Peacock Ave.
Sunnyvale, CA 94087.
2000 Oct 28 Updated for Delphi 4, open array parameters.
This allows the routine to be generalised so that it is no longer
hard-coded to make a specific order of best fit or work with a
specific number of points.
2001 Jan 07 Update Web site address
Copyright © David J Taylor, Edinburgh and others listed above
Web site: www.satsignal.net
E-mail: davidtaylor@writeme.com
}*/
///////////////////////////////////////////////////////////////////////////////
// Modified by CLandone for VC6 Aug 2004
///////////////////////////////////////////////////////////////////////////////
#include <iostream>
using std::vector;
class TPolyFit
{
typedef vector<vector<double> > Matrix;
public:
static double PolyFit2 (const vector<double> &x, // does the work
const vector<double> &y,
vector<double> &coef);
private:
TPolyFit &operator = (const TPolyFit &); // disable assignment
TPolyFit(); // and instantiation
TPolyFit(const TPolyFit&); // and copying
static void Square (const Matrix &x, // Matrix multiplication routine
const vector<double> &y,
Matrix &a, // A = transpose X times X
vector<double> &g, // G = Y times X
const int nrow, const int ncol);
// Forms square coefficient matrix
static bool GaussJordan (Matrix &b, // square matrix of coefficients
const vector<double> &y, // constant vector
vector<double> &coef); // solution vector
// returns false if matrix singular
static bool GaussJordan2(Matrix &b,
const vector<double> &y,
Matrix &w,
vector<vector<int> > &index);
};
// some utility functions
namespace NSUtility
{
inline void swap(double &a, double &b) {double t = a; a = b; b = t;}
void zeroise(vector<double> &array, int n);
void zeroise(vector<int> &array, int n);
void zeroise(vector<vector<double> > &matrix, int m, int n);
void zeroise(vector<vector<int> > &matrix, int m, int n);
inline double sqr(const double &x) {return x * x;}
};
//---------------------------------------------------------------------------
// Implementation
//---------------------------------------------------------------------------
using namespace NSUtility;
//------------------------------------------------------------------------------------------
// main PolyFit routine
double TPolyFit::PolyFit2 (const vector<double> &x,
const vector<double> &y,
vector<double> &coefs)
// nterms = coefs.size()
// npoints = x.size()
{
int i, j;
double xi, yi, yc, srs, sum_y, sum_y2;
Matrix xmatr; // Data matrix
Matrix a;
vector<double> g; // Constant vector
const int npoints(x.size());
const int nterms(coefs.size());
double correl_coef;
zeroise(g, nterms);
zeroise(a, nterms, nterms);
zeroise(xmatr, npoints, nterms);
if (nterms < 1) {
std::cerr << "ERROR: PolyFit called with less than one term" << std::endl;
return 0;
}
if(npoints < 2) {
std::cerr << "ERROR: PolyFit called with less than two points" << std::endl;
return 0;
}
if(npoints != y.size()) {
std::cerr << "ERROR: PolyFit called with x and y of unequal size" << std::endl;
return 0;
}
for(i = 0; i < npoints; ++i)
{
// { setup x matrix }
xi = x[i];
xmatr[i][0] = 1.0; // { first column }
for(j = 1; j < nterms; ++j)
xmatr[i][j] = xmatr [i][j - 1] * xi;
}
Square (xmatr, y, a, g, npoints, nterms);
if(!GaussJordan (a, g, coefs))
return -1;
sum_y = 0.0;
sum_y2 = 0.0;
srs = 0.0;
for(i = 0; i < npoints; ++i)
{
yi = y[i];
yc = 0.0;
for(j = 0; j < nterms; ++j)
yc += coefs [j] * xmatr [i][j];
srs += sqr (yc - yi);
sum_y += yi;
sum_y2 += yi * yi;
}
// If all Y values are the same, avoid dividing by zero
correl_coef = sum_y2 - sqr (sum_y) / npoints;
// Either return 0 or the correct value of correlation coefficient
if (correl_coef != 0)
correl_coef = srs / correl_coef;
if (correl_coef >= 1)
correl_coef = 0.0;
else
correl_coef = sqrt (1.0 - correl_coef);
return correl_coef;
}
//------------------------------------------------------------------------
// Matrix multiplication routine
// A = transpose X times X
// G = Y times X
// Form square coefficient matrix
void TPolyFit::Square (const Matrix &x,
const vector<double> &y,
Matrix &a,
vector<double> &g,
const int nrow,
const int ncol)
{
int i, k, l;
for(k = 0; k < ncol; ++k)
{
for(l = 0; l < k + 1; ++l)
{
a [k][l] = 0.0;
for(i = 0; i < nrow; ++i)
{
a[k][l] += x[i][l] * x [i][k];
if(k != l)
a[l][k] = a[k][l];
}
}
g[k] = 0.0;
for(i = 0; i < nrow; ++i)
g[k] += y[i] * x[i][k];
}
}
//---------------------------------------------------------------------------------
bool TPolyFit::GaussJordan (Matrix &b,
const vector<double> &y,
vector<double> &coef)
//b square matrix of coefficients
//y constant vector
//coef solution vector
//ncol order of matrix got from b.size()
{
/*
{ Gauss Jordan matrix inversion and solution }
{ B (n, n) coefficient matrix becomes inverse }
{ Y (n) original constant vector }
{ W (n, m) constant vector(s) become solution vector }
{ DETERM is the determinant }
{ ERROR = 1 if singular }
{ INDEX (n, 3) }
{ NV is number of constant vectors }
*/
int ncol(b.size());
int irow, icol;
vector<vector<int> >index;
Matrix w;
zeroise(w, ncol, ncol);
zeroise(index, ncol, 3);
if(!GaussJordan2(b, y, w, index))
return false;
// Interchange columns
int m;
for (int i = 0; i < ncol; ++i)
{
m = ncol - i - 1;
if(index [m][0] != index [m][1])
{
irow = index [m][0];
icol = index [m][1];
for(int k = 0; k < ncol; ++k)
swap (b[k][irow], b[k][icol]);
}
}
for(int k = 0; k < ncol; ++k)
{
if(index [k][2] != 0)
{
std::cerr << "ERROR: Error in PolyFit::GaussJordan: matrix is singular" << std::endl;
return false;
}
}
for( int i = 0; i < ncol; ++i)
coef[i] = w[i][0];
return true;
} // end; { procedure GaussJordan }
//----------------------------------------------------------------------------------------------
bool TPolyFit::GaussJordan2(Matrix &b,
const vector<double> &y,
Matrix &w,
vector<vector<int> > &index)
{
//GaussJordan2; // first half of GaussJordan
// actual start of gaussj
double big, t;
double pivot;
double determ;
int irow, icol;
int ncol(b.size());
int nv = 1; // single constant vector
for(int i = 0; i < ncol; ++i)
{
w[i][0] = y[i]; // copy constant vector
index[i][2] = -1;
}
determ = 1.0;
for(int i = 0; i < ncol; ++i)
{
// Search for largest element
big = 0.0;
for(int j = 0; j < ncol; ++j)
{
if(index[j][2] != 0)
{
for(int k = 0; k < ncol; ++k)
{
if(index[k][2] > 0) {
std::cerr << "ERROR: Error in PolyFit::GaussJordan2: matrix is singular" << std::endl;
return false;
}
if(index[k][2] < 0 && fabs(b[j][k]) > big)
{
irow = j;
icol = k;
big = fabs(b[j][k]);
}
} // { k-loop }
}
} // { j-loop }
index [icol][2] = index [icol][2] + 1;
index [i][0] = irow;
index [i][1] = icol;
// Interchange rows to put pivot on diagonal
// GJ3
if(irow != icol)
{
determ = -determ;
for(int m = 0; m < ncol; ++m)
swap (b [irow][m], b[icol][m]);
if (nv > 0)
for (int m = 0; m < nv; ++m)
swap (w[irow][m], w[icol][m]);
} // end GJ3
// divide pivot row by pivot column
pivot = b[icol][icol];
determ *= pivot;
b[icol][icol] = 1.0;
for(int m = 0; m < ncol; ++m)
b[icol][m] /= pivot;
if(nv > 0)
for(int m = 0; m < nv; ++m)
w[icol][m] /= pivot;
// Reduce nonpivot rows
for(int n = 0; n < ncol; ++n)
{
if(n != icol)
{
t = b[n][icol];
b[n][icol] = 0.0;
for(int m = 0; m < ncol; ++m)
b[n][m] -= b[icol][m] * t;
if(nv > 0)
for(int m = 0; m < nv; ++m)
w[n][m] -= w[icol][m] * t;
}
}
} // { i-loop }
return true;
}
//----------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Utility functions
//--------------------------------------------------------------------------
// fills a vector with zeros.
void NSUtility::zeroise(vector<double> &array, int n)
{
array.clear();
for(int j = 0; j < n; ++j)
array.push_back(0);
}
//--------------------------------------------------------------------------
// fills a vector with zeros.
void NSUtility::zeroise(vector<int> &array, int n)
{
array.clear();
for(int j = 0; j < n; ++j)
array.push_back(0);
}
//--------------------------------------------------------------------------
// fills a (m by n) matrix with zeros.
void NSUtility::zeroise(vector<vector<double> > &matrix, int m, int n)
{
vector<double> zero;
zeroise(zero, n);
matrix.clear();
for(int j = 0; j < m; ++j)
matrix.push_back(zero);
}
//--------------------------------------------------------------------------
// fills a (m by n) matrix with zeros.
void NSUtility::zeroise(vector<vector<int> > &matrix, int m, int n)
{
vector<int> zero;
zeroise(zero, n);
matrix.clear();
for(int j = 0; j < m; ++j)
matrix.push_back(zero);
}
//--------------------------------------------------------------------------
#endif

View File

@ -0,0 +1,20 @@
#ifndef NAN_INF_H
#define NAN_INF_H
#include <math.h>
#ifdef sun
#include <ieeefp.h>
#define ISNAN(x) ((sizeof(x)==sizeof(float))?isnanf(x):isnand(x))
#define ISINF(x) (!finite(x))
#else
#define ISNAN(x) isnan(x)
#define ISINF(x) isinf(x)
#endif
#endif

View File

@ -0,0 +1,36 @@
3.0 3.0 3.0 3.0 3.0 3.0 35.0 45.0
53.0 55.0 58.0 113.0 113.0 86.0 67.0 90.0
3.5 3.5 4.0 4.0 4.5 4.5 46.0 59.0
63.0 58.0 58.0 125.0 126.0 110.0 78.0 97.0
4.0 4.0 4.5 4.5 5.0 5.0 48.0 60.0
68.0 65.0 65.0 123.0 123.0 117.0 87.0 108.0
5.0 5.0 5.0 5.5 5.5 5.5 46.0 63.0
70.0 64.0 63.0 116.0 119.0 115.0 97.0 112.0
6.0 6.0 6.0 6.0 6.5 6.5 51.0 69.0
77.0 70.0 71.0 120.0 122.0 122.0 96.0 123.0
11.0 11.0 11.0 11.0 11.0 11.0 64.0 75.0
81.0 79.0 79.0 112.0 114.0 113.0 98.0 115.0
20.0 20.0 20.0 20.0 20.0 20.0 76.0 86.0
93.0 92.0 91.0 104.0 104.5 107.0 97.5 104.0
30.0 30.0 30.0 30.0 30.1 30.2 84.0 96.0
98.0 99.0 96.0 101.0 102.0 99.0 94.0 99.0
30.0 33.4 36.8 40.0 43.0 45.6 100.0 106.0
106.0 108.0 101.0 99.0 98.0 99.0 95.0 95.0
42.0 44.0 46.0 48.0 50.0 51.0 109.0 111.0
110.0 110.0 103.0 95.5 95.5 95.0 92.5 92.0
60.0 61.7 63.5 65.5 67.3 69.2 122.0 124.0
124.0 121.0 103.0 93.2 92.5 92.2 90.0 90.8
70.0 70.1 70.2 70.3 70.4 70.5 137.0 132.0
134.0 128.0 101.0 91.7 90.2 88.8 87.3 85.8
78.0 77.6 77.2 76.8 76.4 76.0 167.0 159.0
152.0 144.0 103.0 89.8 87.7 85.7 83.7 81.8
98.9 97.8 96.7 95.5 94.3 93.2 183.0 172.0
162.0 152.0 102.0 87.5 85.3 83.3 81.3 79.3
160.0 157.0 155.0 152.0 149.0 147.0 186.0 175.0
165.0 156.0 120.0 87.0 84.9 82.8 80.8 79.0
272.0 266.0 260.0 254.0 248.0 242.0 192.0 182.0
170.0 159.0 131.0 88.0 85.8 83.7 81.6 79.6
382.0 372.0 362.0 352.0 343.0 333.0 205.0 192.0
178.0 166.0 138.0 86.2 84.0 82.0 79.8 77.5
770.0 740.0 710.0 680.0 650.0 618.0 226.0 207.0
195.0 180.0 160.0 82.9 80.2 77.7 75.2 72.7

356
libs/qm-dsp/maths/pca/pca.c Normal file
View File

@ -0,0 +1,356 @@
/*********************************/
/* Principal Components Analysis */
/*********************************/
/*********************************************************************/
/* Principal Components Analysis or the Karhunen-Loeve expansion is a
classical method for dimensionality reduction or exploratory data
analysis. One reference among many is: F. Murtagh and A. Heck,
Multivariate Data Analysis, Kluwer Academic, Dordrecht, 1987.
Author:
F. Murtagh
Phone: + 49 89 32006298 (work)
+ 49 89 965307 (home)
Earn/Bitnet: fionn@dgaeso51, fim@dgaipp1s, murtagh@stsci
Span: esomc1::fionn
Internet: murtagh@scivax.stsci.edu
F. Murtagh, Munich, 6 June 1989 */
/*********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "pca.h"
#define SIGN(a, b) ( (b) < 0 ? -fabs(a) : fabs(a) )
/** Variance-covariance matrix: creation *****************************/
/* Create m * m covariance matrix from given n * m data matrix. */
void covcol(double** data, int n, int m, double** symmat)
{
double *mean;
int i, j, j1, j2;
/* Allocate storage for mean vector */
mean = (double*) malloc(m*sizeof(double));
/* Determine mean of column vectors of input data matrix */
for (j = 0; j < m; j++)
{
mean[j] = 0.0;
for (i = 0; i < n; i++)
{
mean[j] += data[i][j];
}
mean[j] /= (double)n;
}
/*
printf("\nMeans of column vectors:\n");
for (j = 0; j < m; j++) {
printf("%12.1f",mean[j]); } printf("\n");
*/
/* Center the column vectors. */
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
data[i][j] -= mean[j];
}
}
/* Calculate the m * m covariance matrix. */
for (j1 = 0; j1 < m; j1++)
{
for (j2 = j1; j2 < m; j2++)
{
symmat[j1][j2] = 0.0;
for (i = 0; i < n; i++)
{
symmat[j1][j2] += data[i][j1] * data[i][j2];
}
symmat[j2][j1] = symmat[j1][j2];
}
}
free(mean);
return;
}
/** Error handler **************************************************/
void erhand(char* err_msg)
{
fprintf(stderr,"Run-time error:\n");
fprintf(stderr,"%s\n", err_msg);
fprintf(stderr,"Exiting to system.\n");
exit(1);
}
/** Reduce a real, symmetric matrix to a symmetric, tridiag. matrix. */
/* Householder reduction of matrix a to tridiagonal form.
Algorithm: Martin et al., Num. Math. 11, 181-195, 1968.
Ref: Smith et al., Matrix Eigensystem Routines -- EISPACK Guide
Springer-Verlag, 1976, pp. 489-494.
W H Press et al., Numerical Recipes in C, Cambridge U P,
1988, pp. 373-374. */
void tred2(double** a, int n, double* d, double* e)
{
int l, k, j, i;
double scale, hh, h, g, f;
for (i = n-1; i >= 1; i--)
{
l = i - 1;
h = scale = 0.0;
if (l > 0)
{
for (k = 0; k <= l; k++)
scale += fabs(a[i][k]);
if (scale == 0.0)
e[i] = a[i][l];
else
{
for (k = 0; k <= l; k++)
{
a[i][k] /= scale;
h += a[i][k] * a[i][k];
}
f = a[i][l];
g = f>0 ? -sqrt(h) : sqrt(h);
e[i] = scale * g;
h -= f * g;
a[i][l] = f - g;
f = 0.0;
for (j = 0; j <= l; j++)
{
a[j][i] = a[i][j]/h;
g = 0.0;
for (k = 0; k <= j; k++)
g += a[j][k] * a[i][k];
for (k = j+1; k <= l; k++)
g += a[k][j] * a[i][k];
e[j] = g / h;
f += e[j] * a[i][j];
}
hh = f / (h + h);
for (j = 0; j <= l; j++)
{
f = a[i][j];
e[j] = g = e[j] - hh * f;
for (k = 0; k <= j; k++)
a[j][k] -= (f * e[k] + g * a[i][k]);
}
}
}
else
e[i] = a[i][l];
d[i] = h;
}
d[0] = 0.0;
e[0] = 0.0;
for (i = 0; i < n; i++)
{
l = i - 1;
if (d[i])
{
for (j = 0; j <= l; j++)
{
g = 0.0;
for (k = 0; k <= l; k++)
g += a[i][k] * a[k][j];
for (k = 0; k <= l; k++)
a[k][j] -= g * a[k][i];
}
}
d[i] = a[i][i];
a[i][i] = 1.0;
for (j = 0; j <= l; j++)
a[j][i] = a[i][j] = 0.0;
}
}
/** Tridiagonal QL algorithm -- Implicit **********************/
void tqli(double* d, double* e, int n, double** z)
{
int m, l, iter, i, k;
double s, r, p, g, f, dd, c, b;
for (i = 1; i < n; i++)
e[i-1] = e[i];
e[n-1] = 0.0;
for (l = 0; l < n; l++)
{
iter = 0;
do
{
for (m = l; m < n-1; m++)
{
dd = fabs(d[m]) + fabs(d[m+1]);
if (fabs(e[m]) + dd == dd) break;
}
if (m != l)
{
if (iter++ == 30) erhand("No convergence in TLQI.");
g = (d[l+1] - d[l]) / (2.0 * e[l]);
r = sqrt((g * g) + 1.0);
g = d[m] - d[l] + e[l] / (g + SIGN(r, g));
s = c = 1.0;
p = 0.0;
for (i = m-1; i >= l; i--)
{
f = s * e[i];
b = c * e[i];
if (fabs(f) >= fabs(g))
{
c = g / f;
r = sqrt((c * c) + 1.0);
e[i+1] = f * r;
c *= (s = 1.0/r);
}
else
{
s = f / g;
r = sqrt((s * s) + 1.0);
e[i+1] = g * r;
s *= (c = 1.0/r);
}
g = d[i+1] - p;
r = (d[i] - g) * s + 2.0 * c * b;
p = s * r;
d[i+1] = g + p;
g = c * r - b;
for (k = 0; k < n; k++)
{
f = z[k][i+1];
z[k][i+1] = s * z[k][i] + c * f;
z[k][i] = c * z[k][i] - s * f;
}
}
d[l] = d[l] - p;
e[l] = g;
e[m] = 0.0;
}
} while (m != l);
}
}
/* In place projection onto basis vectors */
void pca_project(double** data, int n, int m, int ncomponents)
{
int i, j, k, k2;
double **symmat, **symmat2, *evals, *interm;
//TODO: assert ncomponents < m
symmat = (double**) malloc(m*sizeof(double*));
for (i = 0; i < m; i++)
symmat[i] = (double*) malloc(m*sizeof(double));
covcol(data, n, m, symmat);
/*********************************************************************
Eigen-reduction
**********************************************************************/
/* Allocate storage for dummy and new vectors. */
evals = (double*) malloc(m*sizeof(double)); /* Storage alloc. for vector of eigenvalues */
interm = (double*) malloc(m*sizeof(double)); /* Storage alloc. for 'intermediate' vector */
//MALLOC_ARRAY(symmat2,m,m,double);
//for (i = 0; i < m; i++) {
// for (j = 0; j < m; j++) {
// symmat2[i][j] = symmat[i][j]; /* Needed below for col. projections */
// }
//}
tred2(symmat, m, evals, interm); /* Triangular decomposition */
tqli(evals, interm, m, symmat); /* Reduction of sym. trid. matrix */
/* evals now contains the eigenvalues,
columns of symmat now contain the associated eigenvectors. */
/*
printf("\nEigenvalues:\n");
for (j = m-1; j >= 0; j--) {
printf("%18.5f\n", evals[j]); }
printf("\n(Eigenvalues should be strictly positive; limited\n");
printf("precision machine arithmetic may affect this.\n");
printf("Eigenvalues are often expressed as cumulative\n");
printf("percentages, representing the 'percentage variance\n");
printf("explained' by the associated axis or principal component.)\n");
printf("\nEigenvectors:\n");
printf("(First three; their definition in terms of original vbes.)\n");
for (j = 0; j < m; j++) {
for (i = 1; i <= 3; i++) {
printf("%12.4f", symmat[j][m-i]); }
printf("\n"); }
*/
/* Form projections of row-points on prin. components. */
/* Store in 'data', overwriting original data. */
for (i = 0; i < n; i++) {
for (j = 0; j < m; j++) {
interm[j] = data[i][j]; } /* data[i][j] will be overwritten */
for (k = 0; k < ncomponents; k++) {
data[i][k] = 0.0;
for (k2 = 0; k2 < m; k2++) {
data[i][k] += interm[k2] * symmat[k2][m-k-1]; }
}
}
/*
printf("\nProjections of row-points on first 3 prin. comps.:\n");
for (i = 0; i < n; i++) {
for (j = 0; j < 3; j++) {
printf("%12.4f", data[i][j]); }
printf("\n"); }
*/
/* Form projections of col.-points on first three prin. components. */
/* Store in 'symmat2', overwriting what was stored in this. */
//for (j = 0; j < m; j++) {
// for (k = 0; k < m; k++) {
// interm[k] = symmat2[j][k]; } /*symmat2[j][k] will be overwritten*/
// for (i = 0; i < 3; i++) {
// symmat2[j][i] = 0.0;
// for (k2 = 0; k2 < m; k2++) {
// symmat2[j][i] += interm[k2] * symmat[k2][m-i-1]; }
// if (evals[m-i-1] > 0.0005) /* Guard against zero eigenvalue */
// symmat2[j][i] /= sqrt(evals[m-i-1]); /* Rescale */
// else
// symmat2[j][i] = 0.0; /* Standard kludge */
// }
// }
/*
printf("\nProjections of column-points on first 3 prin. comps.:\n");
for (j = 0; j < m; j++) {
for (k = 0; k < 3; k++) {
printf("%12.4f", symmat2[j][k]); }
printf("\n"); }
*/
for (i = 0; i < m; i++)
free(symmat[i]);
free(symmat);
//FREE_ARRAY(symmat2,m);
free(evals);
free(interm);
}

View File

@ -0,0 +1,30 @@
#ifndef _PCA_H
#define _PCA_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* pca.h
*
* Created by Mark Levy on 08/02/2006.
* Copyright 2006 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.
*
*/
void pca_project(double** data, int n, int m, int ncomponents);
#ifdef __cplusplus
}
#endif
#endif

114
libs/qm-dsp/qm-dsp.pro Normal file
View File

@ -0,0 +1,114 @@
TEMPLATE = lib
CONFIG += staticlib warn_on release
CONFIG -= qt
OBJECTS_DIR = tmp_obj
MOC_DIR = tmp_moc
linux-g++* {
QMAKE_CXXFLAGS_RELEASE += -DNDEBUG -O3 -fno-exceptions -fPIC -ffast-math -msse -mfpmath=sse -ftree-vectorize -fomit-frame-pointer
DEFINES += USE_PTHREADS
INCLUDEPATH += ../vamp-plugin-sdk ../qm-dsp
LIBPATH += ../vamp-plugin-sdk/vamp-sdk ../qm-dsp
}
linux-g++-64 {
QMAKE_CXXFLAGS_RELEASE += -msse2
INCLUDEPATH += ../qm-vamp-plugins/build/linux/amd64
}
win32-x-g++ {
QMAKE_CXXFLAGS_RELEASE += -DNDEBUG -O2 -march=pentium3 -msse
INCLUDEPATH += . include ../include
}
macx-g++* {
QMAKE_MAC_SDK=/Developer/SDKs/MacOSX10.4u.sdk
CONFIG += x86 ppc
QMAKE_CXXFLAGS_RELEASE += -O2 -g0 -fvisibility=hidden -I/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/Headers/
INCLUDEPATH += /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/Headers/
DEFINES += USE_PTHREADS
QMAKE_CXXFLAGS_RELEASE += -fvisibility=hidden
}
solaris* {
QMAKE_CXXFLAGS_RELEASE += -DNDEBUG -fast
INCLUDEPATH += /opt/ATLAS3.9.14/include
DEFINES += USE_PTHREADS
}
INCLUDEPATH += .
# Input
HEADERS += base/Pitch.h \
base/Window.h \
dsp/chromagram/Chromagram.h \
dsp/chromagram/ConstantQ.h \
dsp/keydetection/GetKeyMode.h \
dsp/mfcc/MFCC.h \
dsp/onsets/DetectionFunction.h \
dsp/onsets/PeakPicking.h \
dsp/phasevocoder/PhaseVocoder.h \
dsp/rateconversion/Decimator.h \
dsp/rhythm/BeatSpectrum.h \
dsp/segmentation/cluster_melt.h \
dsp/segmentation/ClusterMeltSegmenter.h \
dsp/segmentation/cluster_segmenter.h \
dsp/segmentation/Segmenter.h \
dsp/segmentation/segment.h \
dsp/signalconditioning/DFProcess.h \
dsp/signalconditioning/Filter.h \
dsp/signalconditioning/FiltFilt.h \
dsp/signalconditioning/Framer.h \
dsp/tempotracking/DownBeat.h \
dsp/tempotracking/TempoTrack.h \
dsp/tempotracking/TempoTrackV2.h \
dsp/tonal/ChangeDetectionFunction.h \
dsp/tonal/TCSgram.h \
dsp/tonal/TonalEstimator.h \
dsp/transforms/FFT.h \
dsp/wavelet/Wavelet.h \
hmm/hmm.h \
maths/Correlation.h \
maths/CosineDistance.h \
maths/KLDivergence.h \
maths/MathAliases.h \
maths/MathUtilities.h \
maths/Polyfit.h \
maths/pca/pca.h \
thread/AsynchronousTask.h \
thread/BlockAllocator.h \
thread/Thread.h
SOURCES += base/Pitch.cpp \
dsp/chromagram/Chromagram.cpp \
dsp/chromagram/ConstantQ.cpp \
dsp/keydetection/GetKeyMode.cpp \
dsp/mfcc/MFCC.cpp \
dsp/onsets/DetectionFunction.cpp \
dsp/onsets/PeakPicking.cpp \
dsp/phasevocoder/PhaseVocoder.cpp \
dsp/rateconversion/Decimator.cpp \
dsp/rhythm/BeatSpectrum.cpp \
dsp/segmentation/cluster_melt.c \
dsp/segmentation/ClusterMeltSegmenter.cpp \
dsp/segmentation/cluster_segmenter.c \
dsp/segmentation/Segmenter.cpp \
dsp/signalconditioning/DFProcess.cpp \
dsp/signalconditioning/Filter.cpp \
dsp/signalconditioning/FiltFilt.cpp \
dsp/signalconditioning/Framer.cpp \
dsp/tempotracking/DownBeat.cpp \
dsp/tempotracking/TempoTrack.cpp \
dsp/tempotracking/TempoTrackV2.cpp \
dsp/tonal/ChangeDetectionFunction.cpp \
dsp/tonal/TCSgram.cpp \
dsp/tonal/TonalEstimator.cpp \
dsp/transforms/FFT.cpp \
dsp/wavelet/Wavelet.cpp \
hmm/hmm.c \
maths/Correlation.cpp \
maths/CosineDistance.cpp \
maths/KLDivergence.cpp \
maths/MathUtilities.cpp \
maths/pca/pca.c \
thread/Thread.cpp

View File

@ -0,0 +1,110 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file Copyright 2009 QMUL.
*/
#ifndef _ASYNCHRONOUS_TASK_H_
#define _ASYNCHRONOUS_TASK_H_
#include "Thread.h"
#include <iostream>
/**
* AsynchronousTask provides a thread pattern implementation for
* threads which are used to perform a series of similar operations in
* parallel with other threads of the same type.
*
* For example, a thread used to calculate FFTs of a particular block
* size in the context of a class that needs to calculate many block
* sizes of FFT at once may be a candidate for an AsynchronousTask.
*
* The general use pattern is:
*
* caller -> request thread A calculate something
* caller -> request thread B calculate something
* caller -> request thread C calculate something
* caller -> wait for threads A, B, and C
*
* Here threads A, B, and C may be AsynchronousTasks. An important
* point is that the caller must be prepared to block when waiting for
* these threads to complete (i.e. they are started asynchronously,
* but testing for completion is synchronous).
*/
class AsynchronousTask : public Thread
{
public:
AsynchronousTask() :
m_todo("AsynchronousTask: task to perform"),
m_done("AsynchronousTask: task complete"),
m_inTask(false),
m_finishing(false)
{
start();
}
virtual ~AsynchronousTask()
{
m_todo.lock();
m_finishing = true;
m_todo.signal();
m_todo.unlock();
wait();
}
// Subclass must provide methods to request task and obtain
// results, which the caller calls. The method that requests a
// new task should set up any internal state and call startTask(),
// which then calls back on the subclass implementation of
// performTask from within its work thread. The method that
// obtains results should call awaitTask() and then return any
// results from internal state.
protected:
void startTask() {
m_done.lock();
m_todo.lock();
m_inTask = true;
m_todo.signal();
m_todo.unlock();
}
void awaitTask() {
m_done.wait();
m_done.unlock();
}
virtual void performTask() = 0;
private:
virtual void run() {
m_todo.lock();
while (1) {
while (!m_inTask && !m_finishing) {
m_todo.wait();
}
if (m_finishing) {
m_done.lock();
m_inTask = false;
m_done.signal();
m_done.unlock();
break;
}
performTask();
m_done.lock();
m_inTask = false;
m_done.signal();
m_done.unlock();
}
m_todo.unlock();
}
Condition m_todo;
Condition m_done;
bool m_inTask;
bool m_finishing;
};
#endif

View File

@ -0,0 +1,189 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file is derived from the FSB Allocator by Juha Nieminen. The
underlying method is unchanged, but the class has been refactored
to permit multiple separate allocators (e.g. one per thread)
rather than use a single global one (and to fit house style).
Copyright (c) 2008 Juha Nieminen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef _BLOCK_ALLOCATOR_H_
#define _BLOCK_ALLOCATOR_H_
#include <cstdlib>
/**
* BlockAllocator is a simple allocator for fixed-size (usually small)
* chunks of memory. The size of an element is specified in the
* BlockAllocator constructor, and the functions allocate() and
* deallocate() are used to obtain and release a single element at a
* time.
*
* BlockAllocator may be an appropriate class to use in situations
* involving a very large number of allocations and deallocations of
* simple, identical objects across multiple threads (a hard situation
* for a generic system malloc implementation to handle well). Retain
* one BlockAllocator per thread (the class itself is not
* thread-safe), and ensure that each thread uses its own allocator
* exclusively.
*
* BlockAllocator is based on Juha Nieminen's more general
* FSBAllocator.
*/
class BlockAllocator
{
public:
typedef std::size_t data_t;
BlockAllocator(int elementSize) : m_sz(elementSize) { }
void *
allocate()
{
if (m_freelist.empty()) {
m_freelist.push_back(m_blocks.data.size());
m_blocks.data.push_back(Block(this));
}
const data_t index = m_freelist.back();
Block &block = m_blocks.data[index];
void *retval = block.allocate(index);
if (block.isFull()) m_freelist.pop_back();
return retval;
}
void
deallocate(void *ptr)
{
if (!ptr) return;
data_t *unitPtr = (data_t *)ptr;
const data_t blockIndex = unitPtr[elementSizeInDataUnits()];
Block& block = m_blocks.data[blockIndex];
if (block.isFull()) m_freelist.push_back(blockIndex);
block.deallocate(unitPtr);
}
private:
inline data_t elementsPerBlock() const {
return 512;
}
inline data_t dataSize() const {
return sizeof(data_t);
}
inline data_t elementSizeInDataUnits() const {
return (m_sz + (dataSize() - 1)) / dataSize();
}
inline data_t unitSizeInDataUnits() const {
return elementSizeInDataUnits() + 1;
}
inline data_t blockSizeInDataUnits() const {
return elementsPerBlock() * unitSizeInDataUnits();
}
class Block
{
public:
Block(BlockAllocator *a) :
m_a(a),
m_block(0),
m_firstFreeUnit(data_t(-1)),
m_allocated(0),
m_end(0)
{}
~Block() {
delete[] m_block;
}
bool isFull() const {
return m_allocated == m_a->elementsPerBlock();
}
void clear() {
delete[] m_block;
m_block = 0;
m_firstFreeUnit = data_t(-1);
}
void *allocate(data_t index) {
if (m_firstFreeUnit == data_t(-1)) {
if (!m_block) {
m_block = new data_t[m_a->blockSizeInDataUnits()];
m_end = 0;
}
data_t *retval = m_block + m_end;
m_end += m_a->unitSizeInDataUnits();
retval[m_a->elementSizeInDataUnits()] = index;
++m_allocated;
return retval;
} else {
data_t *retval = m_block + m_firstFreeUnit;
m_firstFreeUnit = *retval;
++m_allocated;
return retval;
}
}
void deallocate(data_t *ptr) {
*ptr = m_firstFreeUnit;
m_firstFreeUnit = ptr - m_block;
if (--m_allocated == 0) clear();
}
private:
const BlockAllocator *m_a;
data_t *m_block;
data_t m_firstFreeUnit;
data_t m_allocated;
data_t m_end;
};
struct Blocks
{
std::vector<Block> data;
Blocks() {
data.reserve(1024);
}
};
const int m_sz;
Blocks m_blocks;
std::vector<data_t> m_freelist;
};
#endif

View File

@ -0,0 +1,643 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright Chris Cannam, used with permission.
*/
#include "Thread.h"
#include <iostream>
#include <cstdlib>
#ifdef USE_PTHREADS
#include <sys/time.h>
#include <time.h>
#endif
using std::cerr;
using std::endl;
using std::string;
#ifdef _WIN32
Thread::Thread() :
m_id(0),
m_extant(false)
{
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: Created thread object " << this << endl;
#endif
}
Thread::~Thread()
{
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: Destroying thread object " << this << ", id " << m_id << endl;
#endif
if (m_extant) {
WaitForSingleObject(m_id, INFINITE);
}
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: Destroyed thread object " << this << endl;
#endif
}
void
Thread::start()
{
m_id = CreateThread(NULL, 0, staticRun, this, 0, 0);
if (!m_id) {
cerr << "ERROR: thread creation failed" << endl;
exit(1);
} else {
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: Created thread " << m_id << " for thread object " << this << endl;
#endif
m_extant = true;
}
}
void
Thread::wait()
{
if (m_extant) {
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: Waiting on thread " << m_id << " for thread object " << this << endl;
#endif
WaitForSingleObject(m_id, INFINITE);
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: Waited on thread " << m_id << " for thread object " << this << endl;
#endif
m_extant = false;
}
}
Thread::Id
Thread::id()
{
return m_id;
}
bool
Thread::threadingAvailable()
{
return true;
}
DWORD
Thread::staticRun(LPVOID arg)
{
Thread *thread = static_cast<Thread *>(arg);
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: " << (void *)GetCurrentThreadId() << ": Running thread " << thread->m_id << " for thread object " << thread << endl;
#endif
thread->run();
return 0;
}
Mutex::Mutex()
#ifndef NO_THREAD_CHECKS
:
m_lockedBy(-1)
#endif
{
m_mutex = CreateMutex(NULL, FALSE, NULL);
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised mutex " << &m_mutex << endl;
#endif
}
Mutex::~Mutex()
{
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying mutex " << &m_mutex << endl;
#endif
CloseHandle(m_mutex);
}
void
Mutex::lock()
{
#ifndef NO_THREAD_CHECKS
DWORD tid = GetCurrentThreadId();
if (m_lockedBy == tid) {
cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl;
}
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl;
#endif
WaitForSingleObject(m_mutex, INFINITE);
#ifndef NO_THREAD_CHECKS
m_lockedBy = tid;
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl;
#endif
}
void
Mutex::unlock()
{
#ifndef NO_THREAD_CHECKS
DWORD tid = GetCurrentThreadId();
if (m_lockedBy != tid) {
cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl;
return;
}
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl;
#endif
#ifndef NO_THREAD_CHECKS
m_lockedBy = -1;
#endif
ReleaseMutex(m_mutex);
}
bool
Mutex::trylock()
{
#ifndef NO_THREAD_CHECKS
DWORD tid = GetCurrentThreadId();
#endif
DWORD result = WaitForSingleObject(m_mutex, 0);
if (result == WAIT_TIMEOUT || result == WAIT_FAILED) {
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl;
#endif
return false;
} else {
#ifndef NO_THREAD_CHECKS
m_lockedBy = tid;
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl;
#endif
return true;
}
}
Condition::Condition(string name) :
m_locked(false)
#ifdef DEBUG_CONDITION
, m_name(name)
#endif
{
m_mutex = CreateMutex(NULL, FALSE, NULL);
m_condition = CreateEvent(NULL, FALSE, FALSE, NULL);
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Initialised condition " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
}
Condition::~Condition()
{
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Destroying condition " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
if (m_locked) ReleaseMutex(m_mutex);
CloseHandle(m_condition);
CloseHandle(m_mutex);
}
void
Condition::lock()
{
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Want to lock " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
WaitForSingleObject(m_mutex, INFINITE);
m_locked = true;
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Locked " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
}
void
Condition::unlock()
{
if (!m_locked) {
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Not locked " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
return;
}
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Unlocking " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
m_locked = false;
ReleaseMutex(m_mutex);
}
void
Condition::wait(int us)
{
if (us == 0) {
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Waiting on " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
SignalObjectAndWait(m_mutex, m_condition, INFINITE, FALSE);
WaitForSingleObject(m_mutex, INFINITE);
} else {
DWORD ms = us / 1000;
if (us > 0 && ms == 0) ms = 1;
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Timed waiting on " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
SignalObjectAndWait(m_mutex, m_condition, ms, FALSE);
WaitForSingleObject(m_mutex, INFINITE);
}
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Wait done on " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
m_locked = true;
}
void
Condition::signal()
{
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)GetCurrentThreadId() << ": Signalling " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
SetEvent(m_condition);
}
#else /* !_WIN32 */
#ifdef USE_PTHREADS
Thread::Thread() :
m_id(0),
m_extant(false)
{
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: Created thread object " << this << endl;
#endif
}
Thread::~Thread()
{
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: Destroying thread object " << this << ", id " << m_id << endl;
#endif
if (m_extant) {
pthread_join(m_id, 0);
}
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: Destroyed thread object " << this << endl;
#endif
}
void
Thread::start()
{
if (pthread_create(&m_id, 0, staticRun, this)) {
cerr << "ERROR: thread creation failed" << endl;
exit(1);
} else {
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: Created thread " << m_id << " for thread object " << this << endl;
#endif
m_extant = true;
}
}
void
Thread::wait()
{
if (m_extant) {
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: Waiting on thread " << m_id << " for thread object " << this << endl;
#endif
pthread_join(m_id, 0);
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: Waited on thread " << m_id << " for thread object " << this << endl;
#endif
m_extant = false;
}
}
Thread::Id
Thread::id()
{
return m_id;
}
bool
Thread::threadingAvailable()
{
return true;
}
void *
Thread::staticRun(void *arg)
{
Thread *thread = static_cast<Thread *>(arg);
#ifdef DEBUG_THREAD
cerr << "THREAD DEBUG: " << (void *)pthread_self() << ": Running thread " << thread->m_id << " for thread object " << thread << endl;
#endif
thread->run();
return 0;
}
Mutex::Mutex()
#ifndef NO_THREAD_CHECKS
:
m_lockedBy(0),
m_locked(false)
#endif
{
pthread_mutex_init(&m_mutex, 0);
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Initialised mutex " << &m_mutex << endl;
#endif
}
Mutex::~Mutex()
{
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Destroying mutex " << &m_mutex << endl;
#endif
pthread_mutex_destroy(&m_mutex);
}
void
Mutex::lock()
{
#ifndef NO_THREAD_CHECKS
pthread_t tid = pthread_self();
if (m_locked && m_lockedBy == tid) {
cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl;
}
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl;
#endif
pthread_mutex_lock(&m_mutex);
#ifndef NO_THREAD_CHECKS
m_lockedBy = tid;
m_locked = true;
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl;
#endif
}
void
Mutex::unlock()
{
#ifndef NO_THREAD_CHECKS
pthread_t tid = pthread_self();
if (!m_locked) {
cerr << "ERROR: Mutex " << &m_mutex << " not locked in unlock" << endl;
return;
} else if (m_lockedBy != tid) {
cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl;
return;
}
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl;
#endif
#ifndef NO_THREAD_CHECKS
m_locked = false;
#endif
pthread_mutex_unlock(&m_mutex);
}
bool
Mutex::trylock()
{
#ifndef NO_THREAD_CHECKS
pthread_t tid = pthread_self();
#endif
if (pthread_mutex_trylock(&m_mutex)) {
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl;
#endif
return false;
} else {
#ifndef NO_THREAD_CHECKS
m_lockedBy = tid;
m_locked = true;
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl;
#endif
return true;
}
}
Condition::Condition(string name) :
m_locked(false)
#ifdef DEBUG_CONDITION
, m_name(name)
#endif
{
pthread_mutex_init(&m_mutex, 0);
pthread_cond_init(&m_condition, 0);
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Initialised condition " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
}
Condition::~Condition()
{
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Destroying condition " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
if (m_locked) pthread_mutex_unlock(&m_mutex);
pthread_cond_destroy(&m_condition);
pthread_mutex_destroy(&m_mutex);
}
void
Condition::lock()
{
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Want to lock " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
pthread_mutex_lock(&m_mutex);
m_locked = true;
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Locked " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
}
void
Condition::unlock()
{
if (!m_locked) {
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Not locked " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
return;
}
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Unlocking " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
m_locked = false;
pthread_mutex_unlock(&m_mutex);
}
void
Condition::wait(int us)
{
if (us == 0) {
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Waiting on " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
pthread_cond_wait(&m_condition, &m_mutex);
} else {
struct timeval now;
gettimeofday(&now, 0);
now.tv_usec += us;
while (now.tv_usec > 1000000) {
now.tv_usec -= 1000000;
++now.tv_sec;
}
struct timespec timeout;
timeout.tv_sec = now.tv_sec;
timeout.tv_nsec = now.tv_usec * 1000;
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Timed waiting on " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
pthread_cond_timedwait(&m_condition, &m_mutex, &timeout);
}
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Wait done on " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
m_locked = true;
}
void
Condition::signal()
{
#ifdef DEBUG_CONDITION
cerr << "CONDITION DEBUG: " << (void *)pthread_self() << ": Signalling " << &m_condition << " \"" << m_name << "\"" << endl;
#endif
pthread_cond_signal(&m_condition);
}
#else /* !USE_PTHREADS */
Thread::Thread()
{
}
Thread::~Thread()
{
}
void
Thread::start()
{
abort();
}
void
Thread::wait()
{
abort();
}
Thread::Id
Thread::id()
{
abort();
}
bool
Thread::threadingAvailable()
{
return false;
}
Mutex::Mutex()
{
}
Mutex::~Mutex()
{
}
void
Mutex::lock()
{
abort();
}
void
Mutex::unlock()
{
abort();
}
bool
Mutex::trylock()
{
abort();
}
Condition::Condition(const char *)
{
}
Condition::~Condition()
{
}
void
Condition::lock()
{
abort();
}
void
Condition::wait(int us)
{
abort();
}
void
Condition::signal()
{
abort();
}
#endif /* !USE_PTHREADS */
#endif /* !_WIN32 */
MutexLocker::MutexLocker(Mutex *mutex) :
m_mutex(mutex)
{
if (m_mutex) {
m_mutex->lock();
}
}
MutexLocker::~MutexLocker()
{
if (m_mutex) {
m_mutex->unlock();
}
}

149
libs/qm-dsp/thread/Thread.h Normal file
View File

@ -0,0 +1,149 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
QM DSP Library
Centre for Digital Music, Queen Mary, University of London.
This file copyright Chris Cannam, used with permission.
*/
#ifndef _THREAD_H_
#define _THREAD_H_
#ifdef _WIN32
#include <windows.h>
#else /* !_WIN32 */
#ifdef USE_PTHREADS
#include <pthread.h>
#endif /* USE_PTHREADS */
#endif /* !_WIN32 */
#include <string>
//#define DEBUG_THREAD 1
//#define DEBUG_MUTEX 1
//#define DEBUG_CONDITION 1
class Thread
{
public:
#ifdef _WIN32
typedef HANDLE Id;
#else
#ifdef USE_PTHREADS
typedef pthread_t Id;
#endif
#endif
Thread();
virtual ~Thread();
Id id();
void start();
void wait();
static bool threadingAvailable();
protected:
virtual void run() = 0;
private:
#ifdef _WIN32
HANDLE m_id;
bool m_extant;
static DWORD WINAPI staticRun(LPVOID lpParam);
#else
#ifdef USE_PTHREADS
pthread_t m_id;
bool m_extant;
static void *staticRun(void *);
#endif
#endif
};
class Mutex
{
public:
Mutex();
~Mutex();
void lock();
void unlock();
bool trylock();
private:
#ifdef _WIN32
HANDLE m_mutex;
#ifndef NO_THREAD_CHECKS
DWORD m_lockedBy;
#endif
#else
#ifdef USE_PTHREADS
pthread_mutex_t m_mutex;
#ifndef NO_THREAD_CHECKS
pthread_t m_lockedBy;
bool m_locked;
#endif
#endif
#endif
};
class MutexLocker
{
public:
MutexLocker(Mutex *);
~MutexLocker();
private:
Mutex *m_mutex;
};
class Condition
{
public:
Condition(std::string name);
~Condition();
// Condition bundles a pthread-style condition variable and mutex
// into one class.
// To wait on a condition, call lock(), test termination variables
// as appropriate, and then wait(). The condition will be
// unlocked for the duration of the wait() call, which will end
// when the condition is signalled. The condition will be locked
// again when wait() returns.
//
// To signal a condition, call signal(). If the waiting thread
// will be performing tests between its own lock() and wait(),
// then the signalling thread should also lock() before it signals
// (and then unlock afterwards). If the signalling thread always
// locks the mutex during signalling, then the waiting thread
// knows that signals will only happen during wait() and not be
// missed at other times.
void lock();
void unlock();
void wait(int us = 0);
void signal();
private:
#ifdef _WIN32
HANDLE m_mutex;
HANDLE m_condition;
bool m_locked;
#else
#ifdef USE_PTHREADS
pthread_mutex_t m_mutex;
pthread_cond_t m_condition;
bool m_locked;
#endif
#endif
#ifdef DEBUG_CONDITION
std::string m_name;
#endif
};
#endif

59
libs/qm-dsp/wscript Normal file
View File

@ -0,0 +1,59 @@
#!/usr/bin/env python
import autowaf
import os
# Version of this package (even if built as a child)
QM_DSP_VERSION = '0.0.0'
# Library version (UNIX style major, minor, micro)
# major increment <=> incompatible changes
# minor increment <=> compatible changes (additions)
# micro increment <=> no interface changes
QM_DSP_LIB_VERSION = '0.0.0'
# Variables for 'waf dist'
APPNAME = 'qm-dsp'
VERSION = QM_DSP_VERSION
# Mandatory variables
srcdir = '.'
blddir = 'build'
def set_options(opt):
autowaf.set_options(opt)
def configure(conf):
autowaf.configure(conf)
conf.check_tool('compiler_cxx')
def build(bld):
# Host Library
obj = bld.new_task_gen('cxx', 'shlib')
obj.source = '''
dsp/onsets/DetectionFunction.cpp
dsp/onsets/PeakPicking.cpp
dsp/phasevocoder/PhaseVocoder.cpp
dsp/rateconversion/Decimator.cpp
dsp/rhythm/BeatSpectrum.cpp
dsp/signalconditioning/DFProcess.cpp
dsp/signalconditioning/Filter.cpp
dsp/signalconditioning/FiltFilt.cpp
dsp/signalconditioning/Framer.cpp
dsp/transforms/FFT.cpp
dsp/wavelet/Wavelet.cpp
maths/Correlation.cpp
maths/CosineDistance.cpp
maths/KLDivergence.cpp
maths/MathUtilities.cpp
base/Pitch.cpp
'''
obj.export_incdirs = ['.']
obj.includes = ['.']
obj.name = 'libqmdsp'
obj.target = 'qmdsp'
obj.vnum = QM_DSP_VERSION
obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
def shutdown():
autowaf.shutdown()