summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDaniel Schürmann <daschuer@mixxx.org>2019-06-03 00:17:56 +0200
committerDaniel Schürmann <daschuer@mixxx.org>2019-06-03 01:41:18 +0200
commita6b58824fa2fd5a67a7d7feff79ba1e01e2cc2ad (patch)
tree9d893e45d7e4e456cf3e4d4a5686df9fafedd11e /lib
parenta4db708c987084a6c990125232eabdff35fdba51 (diff)
Update qm-dsp to current master https://github.com/c4dm/qm-dsp/commit/4c406d9990bc42e5e298dc28eb8b897095275683
Diffstat (limited to 'lib')
-rw-r--r--lib/qm-dsp/CONTRIBUTING.md79
-rw-r--r--lib/qm-dsp/README.md59
-rw-r--r--lib/qm-dsp/README.txt35
-rw-r--r--lib/qm-dsp/base/Restrict.h17
-rw-r--r--lib/qm-dsp/dsp/chromagram/Chromagram.cpp40
-rw-r--r--lib/qm-dsp/dsp/chromagram/Chromagram.h53
-rw-r--r--lib/qm-dsp/dsp/chromagram/ConstantQ.cpp32
-rw-r--r--lib/qm-dsp/dsp/chromagram/ConstantQ.h4
-rw-r--r--lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp259
-rw-r--r--lib/qm-dsp/dsp/keydetection/GetKeyMode.h12
-rw-r--r--lib/qm-dsp/dsp/rateconversion/DecimatorB.cpp1
-rw-r--r--lib/qm-dsp/dsp/rateconversion/Resampler.cpp64
-rw-r--r--lib/qm-dsp/dsp/rateconversion/Resampler.h1
-rw-r--r--lib/qm-dsp/dsp/segmentation/ClusterMeltSegmenter.cpp19
-rw-r--r--lib/qm-dsp/dsp/segmentation/Segmenter.cpp17
-rw-r--r--lib/qm-dsp/dsp/segmentation/cluster_melt.c4
-rw-r--r--lib/qm-dsp/dsp/segmentation/cluster_segmenter.c2
-rw-r--r--lib/qm-dsp/dsp/signalconditioning/DFProcess.cpp15
-rw-r--r--lib/qm-dsp/dsp/signalconditioning/DFProcess.h2
-rw-r--r--lib/qm-dsp/dsp/signalconditioning/FiltFilt.cpp57
-rw-r--r--lib/qm-dsp/dsp/signalconditioning/FiltFilt.h17
-rw-r--r--lib/qm-dsp/dsp/signalconditioning/Filter.cpp148
-rw-r--r--lib/qm-dsp/dsp/signalconditioning/Filter.h72
-rw-r--r--lib/qm-dsp/dsp/tempotracking/DownBeat.cpp2
-rw-r--r--lib/qm-dsp/dsp/tempotracking/TempoTrack.cpp52
-rw-r--r--lib/qm-dsp/dsp/tempotracking/TempoTrack.h36
-rw-r--r--lib/qm-dsp/dsp/tonal/TCSgram.cpp2
-rw-r--r--lib/qm-dsp/dsp/tonal/TonalEstimator.h4
-rw-r--r--lib/qm-dsp/dsp/transforms/DCT.cpp91
-rw-r--r--lib/qm-dsp/dsp/transforms/DCT.h85
-rw-r--r--lib/qm-dsp/dsp/transforms/FFT.cpp4
-rw-r--r--lib/qm-dsp/dsp/transforms/FFT.h6
-rw-r--r--lib/qm-dsp/dsp/wavelet/Wavelet.cpp11
-rw-r--r--lib/qm-dsp/dsp/wavelet/Wavelet.h4
-rw-r--r--lib/qm-dsp/ext/kissfft/CHANGELOG4
-rw-r--r--lib/qm-dsp/ext/kissfft/README134
-rw-r--r--lib/qm-dsp/ext/kissfft/README.simd78
-rw-r--r--lib/qm-dsp/ext/kissfft/TIPS39
-rw-r--r--lib/qm-dsp/ext/kissfft/kiss_fft.c5
-rw-r--r--lib/qm-dsp/ext/kissfft/kissfft.hh300
-rw-r--r--lib/qm-dsp/ext/kissfft/tools/kiss_fftr.c (renamed from lib/qm-dsp/ext/kissfft/kiss_fftr.c)0
-rw-r--r--lib/qm-dsp/ext/kissfft/tools/kiss_fftr.h (renamed from lib/qm-dsp/ext/kissfft/kiss_fftr.h)0
-rw-r--r--lib/qm-dsp/key_rounding.patch253
-rw-r--r--lib/qm-dsp/maths/CosineDistance.cpp2
-rw-r--r--lib/qm-dsp/maths/MathUtilities.cpp84
-rw-r--r--lib/qm-dsp/maths/MathUtilities.h54
-rw-r--r--lib/qm-dsp/maths/Polyfit.h103
-rw-r--r--lib/qm-dsp/maths/pca/pca.c2
48 files changed, 1533 insertions, 831 deletions
diff --git a/lib/qm-dsp/CONTRIBUTING.md b/lib/qm-dsp/CONTRIBUTING.md
new file mode 100644
index 0000000000..6f6229e610
--- /dev/null
+++ b/lib/qm-dsp/CONTRIBUTING.md
@@ -0,0 +1,79 @@
+
+Contributing
+============
+
+The qm-dsp library is maintained in a Github repository at
+https://github.com/c4dm/qm-dsp.
+
+
+Reporting bugs
+--------------
+
+Please use Github issues for bug reports. Try to make them as specific
+as possible. For example, describe an input that triggers some
+particular behaviour, and tell us how that behaviour differs from what
+you expected.
+
+If your bug can be reproduced by processing an audio file using one of
+the QM Vamp Plugins (https://github.com/c4dm/qm-vamp-plugins), which
+are built using this library, that might be a good way to illustrate
+the problem.
+
+
+Pull requests
+-------------
+
+We're happy to see pull requests, and can pull them directly in some
+circumstances.
+
+ * Please make sure your change compiles without warnings and passes
+ the existing tests.
+
+ * Please follow the code style guidelines (see below).
+
+ * Please make it as easy as possible to verify the behaviour of the
+ pull request, for example by adding a new test in the `tests`
+ directory. This library has only limited test coverage, but we
+ would like to expand it, and prefer not to make changes unless they
+ are backed by tests.
+
+ * Please provide your changes under terms which permit Queen Mary
+ University of London to relicense the code for commercial
+ purposes. The qm-dsp library as a whole is provided under the GPL,
+ but QM also make commercial licences available separately, and
+ cannot accept any pull request whose copyright status would prevent
+ that. In practice, this means any non-trivial change not
+ originating from QM must be explicitly licensed using a BSD-like
+ licence text, either in the source file itself or in an
+ accompanying file. See `thread/BlockAllocator.h` for an example of
+ typical language.
+
+Please note also that fixes which change the behaviour of the existing
+QM Vamp Plugins will need particularly close scrutiny - these are
+reasonably widely used and, even where they have defects, changes may
+cause problems for users and will at least need to be documented with
+the plugins. For this reason it may take some time for such changes to
+be reviewed or integrated.
+
+
+Code style
+----------
+
+ * C++ code must compile with the C++98 standard, except for the unit
+ tests which are C++14
+
+ * Classes are named `LikeThis` - functions, methods, and local
+ variables `likeThis` - class member variables `m_likeThis`
+
+ * Indentation is four spaces at a time (no tabs)
+
+ * The opening brace for a block goes at the end of the line, except
+ at the start of a function or class definition where it gets a line
+ of its own
+
+ * Please use braces around any conditional or loop block that
+ occupies its own line
+
+Some of the older code in this library does not follow these
+guidelines - usually this means the code needs to be updated.
+
diff --git a/lib/qm-dsp/README.md b/lib/qm-dsp/README.md
new file mode 100644
index 0000000000..20bcb60f04
--- /dev/null
+++ b/lib/qm-dsp/README.md
@@ -0,0 +1,59 @@
+
+QM-DSP library
+==============
+
+This is a C++ library of functions for Digital Signal Processing and
+Music Informatics purposes developed in the [Centre for Digital
+Music](http://c4dm.eecs.qmul.ac.uk) at Queen Mary, University of
+London.
+
+It is used by [QM Vamp Plugins](http://isophonics.net/QMVampPlugins)
+amongst other things.
+
+Despite the assertive name "qm-dsp", it is not "the official QM DSP
+library", just one library for DSP that happens to have been written
+at QM. It got this name because nothing else was using it at the time.
+
+
+Compiling the library
+---------------------
+
+ - Linux: `make -f build/linux/Makefile.linux64`
+
+ - Mac: `make -f build/osx/Makefile.osx`
+
+ - Windows (MSVC): Use the project file `build/msvc/QMDSP.vcxproj`
+
+To build and run unit tests as well, add the `test` target to your
+Make invocation, e.g. `make -f build/linux/Makefile.linux64
+test`. Tests require the Boost library.
+
+
+Licence
+-------
+
+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.
+
+This code is Copyright (c) 2006-2019 Queen Mary, University of London,
+with the following exceptions:
+
+ - `ext/kissfft` - Copyright (c) 2003-2010 Mark Borgerding
+
+ - `maths/pca/pca.c` - Fionn Murtagh, from StatLib, used with permission
+
+ - `maths/Polyfit.h` - by 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 a BSD-style license
+
+See individual files for further authorship details.
+
+If you wish to use this code in a proprietary application or product
+for which the terms of the GPL are not appropriate, please contact QM
+Innovation https://www.qminnovation.co.uk/ for licensing terms.
diff --git a/lib/qm-dsp/README.txt b/lib/qm-dsp/README.txt
deleted file mode 100644
index 6927c7a1b8..0000000000
--- a/lib/qm-dsp/README.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-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-2015 Queen Mary, University of London,
-with the following exceptions:
-
-ext/kissfft -- Copyright (c) 2003-2010 Mark Borgerding
-
-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.
-
-
diff --git a/lib/qm-dsp/base/Restrict.h b/lib/qm-dsp/base/Restrict.h
new file mode 100644
index 0000000000..723a8b3b67
--- /dev/null
+++ b/lib/qm-dsp/base/Restrict.h
@@ -0,0 +1,17 @@
+
+#ifndef QM_DSP_RESTRICT_H
+#define QM_DSP_RESTRICT_H
+
+#ifdef _MSC_VER
+#define QM_R__ __restrict
+#endif
+
+#ifdef __GNUC__
+#define QM_R__ __restrict__
+#endif
+
+#ifndef QM_R__
+#define QM_R__
+#endif
+
+#endif
diff --git a/lib/qm-dsp/dsp/chromagram/Chromagram.cpp b/lib/qm-dsp/dsp/chromagram/Chromagram.cpp
index 5ba2a762de..9f40b1d2f1 100644
--- a/lib/qm-dsp/dsp/chromagram/Chromagram.cpp
+++ b/lib/qm-dsp/dsp/chromagram/Chromagram.cpp
@@ -33,8 +33,9 @@ int Chromagram::initialise( ChromaConfig Config )
m_BPO = Config.BPO; // bins per octave
m_normalise = Config.normalise; // if frame normalisation is required
- // No. of constant Q bins, extended to a full octave
- m_uK = m_BPO * (unsigned int)ceil(log(m_FMax/m_FMin)/log(2.0));
+ // Extend range to a full octave
+ double octaves = log(m_FMax / m_FMin) / log(2.0);
+ m_FMax = m_FMin * pow(2.0, ceil(octaves));
// Create array for chroma result
m_chromadata = new double[ m_BPO ];
@@ -53,6 +54,9 @@ int Chromagram::initialise( ChromaConfig Config )
// Initialise ConstantQ operator
m_ConstantQ = new ConstantQ( ConstantQConfig );
+ // No. of constant Q bins
+ m_uK = m_ConstantQ->getK();
+
// Initialise working arrays
m_frameSize = m_ConstantQ->getfftlength();
m_hopSize = m_ConstantQ->gethop();
@@ -112,7 +116,7 @@ void Chromagram::unityNormalise(double *src)
MathUtilities::getFrameMinMax( src, m_BPO, & min, &max );
- for( unsigned int i = 0; i < m_BPO; i++ )
+ for (int i = 0; i < m_BPO; i++)
{
val = src[ i ] / max;
@@ -121,7 +125,7 @@ void Chromagram::unityNormalise(double *src)
}
-double* Chromagram::process( const double *data )
+double *Chromagram::process(const double *data)
{
if (!m_skGenerated) {
// Generate CQ Kernel
@@ -134,17 +138,25 @@ double* Chromagram::process( const double *data )
m_windowbuf = new double[m_frameSize];
}
- for (unsigned int i = 0; i < m_frameSize; ++i) {
+ for (int i = 0; i < m_frameSize; ++i) {
m_windowbuf[i] = data[i];
}
m_window->cut(m_windowbuf);
+ // The frequency-domain version expects pre-fftshifted input - so
+ // we must do the same here
+ for (int i = 0; i < m_frameSize/2; ++i) {
+ double tmp = m_windowbuf[i];
+ m_windowbuf[i] = m_windowbuf[i + m_frameSize/2];
+ m_windowbuf[i + m_frameSize/2] = tmp;
+ }
+
m_FFT->forward(m_windowbuf, m_FFTRe, m_FFTIm);
return process(m_FFTRe, m_FFTIm);
}
-double* Chromagram::process( const double *real, const double *imag )
+double *Chromagram::process(const double *real, const double *imag)
{
if (!m_skGenerated) {
// Generate CQ Kernel
@@ -153,20 +165,20 @@ double* Chromagram::process( const double *real, const double *imag )
}
// initialise chromadata to 0
- for (unsigned i = 0; i < m_BPO; i++) m_chromadata[i] = 0;
+ for (int i = 0; i < m_BPO; i++) m_chromadata[i] = 0;
// Calculate ConstantQ frame
m_ConstantQ->process( real, imag, m_CQRe, m_CQIm );
// add each octave of cq data into Chromagram
- const unsigned octaves = m_uK / m_BPO;
- for (unsigned octave = 0; octave < octaves; octave++)
+ const int octaves = m_uK / m_BPO;
+ for (int 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 ]);
- }
+ int firstBin = octave*m_BPO;
+ for (int 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);
diff --git a/lib/qm-dsp/dsp/chromagram/Chromagram.h b/lib/qm-dsp/dsp/chromagram/Chromagram.h
index b2ad72e0ac..ca68ee9071 100644
--- a/lib/qm-dsp/dsp/chromagram/Chromagram.h
+++ b/lib/qm-dsp/dsp/chromagram/Chromagram.h
@@ -20,11 +20,11 @@
#include "base/Window.h"
#include "ConstantQ.h"
-struct ChromaConfig{
+struct ChromaConfig {
double FS;
double min;
double max;
- unsigned int BPO;
+ int BPO;
double CQThresh;
MathUtilities::NormaliseType normalise;
};
@@ -35,19 +35,44 @@ 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 );
+
+ /**
+ * Process a time-domain input signal of length equal to
+ * getFrameSize().
+ *
+ * The returned buffer contains the chromagram values indexed by
+ * bin, with the number of values corresponding to the BPO field
+ * in the ChromaConfig supplied at construction. It is owned by
+ * the Chromagram object and is reused from one process call to
+ * the next.
+ */
+ double *process(const double *data);
+
+ /**
+ * Process a frequency-domain input signal generated from a
+ * time-domain signal of length equal to getFrameSize() that has
+ * been windowed and "fftshifted" to place the zero index in the
+ * centre of the frame. The real and imag buffers must each
+ * contain the full getFrameSize() frequency bins.
+ *
+ * The returned buffer contains the chromagram values indexed by
+ * bin, with the number of values corresponding to the BPO field
+ * in the ChromaConfig supplied at construction. It is owned by
+ * the Chromagram object and is reused from one process call to
+ * the next.
+ */
+ double *process(const double *real, const double *imag);
+
+ 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; }
-
+ int getK() { return m_uK;}
+ int getFrameSize() { return m_frameSize; }
+ int getHopSize() { return m_hopSize; }
+
private:
int initialise( ChromaConfig Config );
int deInitialise();
@@ -58,13 +83,13 @@ private:
double* m_chromadata;
double m_FMin;
double m_FMax;
- unsigned int m_BPO;
- unsigned int m_uK;
+ int m_BPO;
+ int m_uK;
MathUtilities::NormaliseType m_normalise;
- unsigned int m_frameSize;
- unsigned int m_hopSize;
+ int m_frameSize;
+ int m_hopSize;
FFTReal* m_FFT;
ConstantQ* m_ConstantQ;
diff --git a/lib/qm-dsp/dsp/chromagram/ConstantQ.cpp b/lib/qm-dsp/dsp/chromagram/ConstantQ.cpp
index f2129f2e6f..4585ddc236 100644
--- a/lib/qm-dsp/dsp/chromagram/ConstantQ.cpp
+++ b/lib/qm-dsp/dsp/chromagram/ConstantQ.cpp
@@ -125,18 +125,17 @@ void ConstantQ::sparsekernel()
hammingWindowIm[u] = 0;
}
- const double samplesPerCycle =
- m_FS / (m_FMin * pow(2, (double)k / (double)m_BPO));
+ // Computing a hamming window
+ const unsigned hammingLength = (int) ceil( m_dQ * m_FS / ( m_FMin * pow(2,((double)(k))/(double)m_BPO)));
- // Computing a hamming window
- const unsigned hammingLength = (int) ceil(
- m_dQ * samplesPerCycle);
+// cerr << "k = " << k << ", q = " << m_dQ << ", m_FMin = " << m_FMin << ", hammingLength = " << hammingLength << " (rounded up from " << (m_dQ * m_FS / ( m_FMin * pow(2,((double)(k))/(double)m_BPO))) << ")" << endl;
+
unsigned origin = m_FFTLength/2 - hammingLength/2;
for (unsigned i=0; i<hammingLength; i++)
{
- const double angle = 2*PI*i/samplesPerCycle;
+ 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;
@@ -144,10 +143,6 @@ void ConstantQ::sparsekernel()
hammingWindowIm[ origin + i ] = absol*imag;
}
- /* This code splits the hanning window and moves it to the beginning
- and the end, creating an empty gap in the middle.
- It is disabled, because it results in wrong results,
- when tested with sin waves centered on a bin frequency.
for (unsigned i = 0; i < m_FFTLength/2; ++i) {
double temp = hammingWindowRe[i];
hammingWindowRe[i] = hammingWindowRe[i + m_FFTLength/2];
@@ -156,7 +151,6 @@ void ConstantQ::sparsekernel()
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 );
@@ -168,7 +162,7 @@ void ConstantQ::sparsekernel()
const double squaredBin = squaredModule( transfHammingWindowRe[ j ], transfHammingWindowIm[ j ]);
if (squaredBin <= squareThreshold) continue;
- // Insert non-zero position indexes, doubled because they are floats
+ // Insert non-zero position indexes
sk->is.push_back(j);
sk->js.push_back(k);
@@ -280,6 +274,7 @@ double* ConstantQ::process( const double* fftdata )
{
const unsigned row = cqbin[i];
const unsigned col = fftbin[i];
+ if (col == 0) continue;
const double & r1 = real[i];
const double & i1 = imag[i];
const double & r2 = fftdata[ (2*m_FFTLength) - 2*col - 2 ];
@@ -301,17 +296,15 @@ void ConstantQ::initialise( CQConfig Config )
m_BPO = Config.BPO; // bins per octave
m_CQThresh = Config.CQThresh;// ConstantQ threshold for kernel generation
- // Work out Q value for Filter bank
- m_dQ = 1/(pow(2,(1/(double)m_BPO))-1);
- // No. of constant Q bins, extended to a full octave
- m_uK = m_BPO * (unsigned int)ceil(log(m_FMax/m_FMin)/log(2.0));
+ 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
+ m_hop = m_FFTLength/8;
// std::cerr << "ConstantQ::initialise: -> fft length = " << m_FFTLength << ", hop = " << m_hop << std::endl;
@@ -351,10 +344,11 @@ void ConstantQ::process(const double *FFTRe, const double* FFTIm,
{
const unsigned row = cqbin[i];
const unsigned col = fftbin[i];
+ if (col == 0) continue;
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 ];
+ const double & r2 = FFTRe[ m_FFTLength - col ];
+ const double & i2 = FFTIm[ m_FFTLength - col ];
// add the multiplication
CQRe[ row ] += (r1*r2 - i1*i2);
CQIm[ row ] += (r1*i2 + i1*r2);
diff --git a/lib/qm-dsp/dsp/chromagram/ConstantQ.h b/lib/qm-dsp/dsp/chromagram/ConstantQ.h
index bd666ddd6f..7507a1f964 100644
--- a/lib/qm-dsp/dsp/chromagram/ConstantQ.h
+++ b/lib/qm-dsp/dsp/chromagram/ConstantQ.h
@@ -20,8 +20,8 @@
#include "maths/MathAliases.h"
#include "maths/MathUtilities.h"
-struct CQConfig{
- double FS; // samplerate
+struct CQConfig {
+ double FS; // samplerate
double min; // minimum frequency
double max; // maximum frequency
unsigned int BPO; // bins per octave
diff --git a/lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp b/lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp
index 7407c43feb..cb8bc2477a 100644
--- a/lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp
+++ b/lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp
@@ -1,7 +1,12 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
- Copyright (c) 2005 Centre for Digital Music ( C4DM )
- Queen Mary Univesrity of London
+ QM DSP Library
+
+ Centre for Digital Music, Queen Mary, University of London.
+ This file 2005-2006 Christian Landone and Katy Noland.
+
+ Fixes to correct chroma offsets and for thread safety contributed
+ by Daniel Schürmann.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -9,9 +14,6 @@
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
*/
-// GetKeyMode.cpp: implementation of the CGetKeyMode class.
-//
-//////////////////////////////////////////////////////////////////////
#include "GetKeyMode.h"
#include "maths/MathUtilities.h"
@@ -22,18 +24,20 @@
#include <cstring>
#include <cstdlib>
+static const int kBinsPerOctave = 36;
+
// 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};
+static double MajProfile[kBinsPerOctave] = {
+ 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[kBinsPerOctave] = {
+ 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};
//
@@ -42,7 +46,7 @@ static double MinProfile[36] =
//////////////////////////////////////////////////////////////////////
GetKeyMode::GetKeyMode( int sampleRate, float tuningFrequency,
- double hpcpAverage, double medianAverage ) :
+ double hpcpAverage, double medianAverage ) :
m_hpcpAverage( hpcpAverage ),
m_medianAverage( medianAverage ),
m_ChrPointer(0),
@@ -51,7 +55,6 @@ GetKeyMode::GetKeyMode( int sampleRate, float tuningFrequency,
m_MeanHPCP(0),
m_MajCorr(0),
m_MinCorr(0),
- m_Keys(0),
m_MedianFilterBuffer(0),
m_SortedBuffer(0),
m_keyStrengths(0)
@@ -61,16 +64,16 @@ GetKeyMode::GetKeyMode( int sampleRate, float tuningFrequency,
// Chromagram configuration parameters
m_ChromaConfig.normalise = MathUtilities::NormaliseUnitMax;
m_ChromaConfig.FS = sampleRate/(double)m_DecimationFactor;
+ if (m_ChromaConfig.FS < 1) {
+ m_ChromaConfig.FS = 1;
+ }
// Set C3 (= MIDI #48) as our base:
// This implies that key = 1 => Cmaj, key = 12 => Bmaj, key = 13 => Cmin, etc.
- m_ChromaConfig.min = Pitch::getFrequencyForPitch
- (48, 0, tuningFrequency);
- // C7 (= MIDI #96) is the exclusive maximum key:
- m_ChromaConfig.max = Pitch::getFrequencyForPitch
- (96, 0, tuningFrequency);
+ m_ChromaConfig.min = Pitch::getFrequencyForPitch( 48, 0, tuni