Skip to content

Commit

Permalink
shift chroma one bin, to have always three bins per note
Browse files Browse the repository at this point in the history
  • Loading branch information
daschuer committed Jun 3, 2019
1 parent 2c42cfc commit 37460c0
Show file tree
Hide file tree
Showing 2 changed files with 274 additions and 17 deletions.
22 changes: 10 additions & 12 deletions lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,9 @@ GetKeyMode::GetKeyMode( int sampleRate, float tuningFrequency,

// 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 );
m_ChromaConfig.max = Pitch::getFrequencyForPitch( 96, 0, tuningFrequency );
const float centsOffset = -12.0f / kBinsPerOctave * 100; // 3 bins per note, start with the first
m_ChromaConfig.min = Pitch::getFrequencyForPitch( 48, centsOffset, tuningFrequency );
m_ChromaConfig.max = Pitch::getFrequencyForPitch( 96, centsOffset, tuningFrequency );

m_ChromaConfig.BPO = kBinsPerOctave;
m_ChromaConfig.CQThresh = 0.0054;
Expand Down Expand Up @@ -186,14 +187,13 @@ int GetKeyMode::process(double *PCMData)

m_ChrPointer = m_Chroma->process( m_DecimatedBuffer );

/*
std::cout << "raw chroma: ";
for (int ii = 0; ii < kBinsPerOctave; ++ii) {
if (ii % (kBinsPerOctave/12) == 0) std::cout << "\n";
std::cout << m_ChrPointer[ii] << " ";
}
std::cout << std::endl;
*/

// populate hpcp values;
int cbidx;
for( j = 0; j < kBinsPerOctave; j++ ) {
Expand Down Expand Up @@ -232,7 +232,7 @@ int GetKeyMode::process(double *PCMData)
/*
// filtered and normalized chromagram
for (unsigned int ii = 0; ii < m_BPO; ++ii) {
double value = m_MeanHPCP[(ii+m_BPO-1) % m_BPO];
double value = m_MeanHPCP[ii];
if (value > 0 && maxNoteValue > 0.01) {
if (value > 0.99) {
std::cout << "Î";
Expand Down Expand Up @@ -263,15 +263,13 @@ int GetKeyMode::process(double *PCMData)
*/



for( k = 0; k < kBinsPerOctave; k++ )
{
// The Cromagram has the center of C at bin 0, while the major
// and minor profiles have the center of C at 1. We want to have
// the correlation for C result also at 1.
// To achieve this we have to shift two times:
m_MajCorr[k] = krumCorr( m_MeanHPCP, m_MajProfileNorm, (int)k - 2, kBinsPerOctave );
m_MinCorr[k] = krumCorr( m_MeanHPCP, m_MinProfileNorm, (int)k - 2, kBinsPerOctave );
// The cromagram and the major and minor profiles have the has the
// center of C at bin 1. We want to have the correlation for C result
// also at 1. To achieve this we have to shift by one:
m_MajCorr[k] = krumCorr( m_MeanHPCP, m_MajProfileNorm, (int)k - 1, kBinsPerOctave );
m_MinCorr[k] = krumCorr( m_MeanHPCP, m_MinProfileNorm, (int)k - 1, kBinsPerOctave );
}

/*
Expand Down
269 changes: 264 additions & 5 deletions lib/qm-dsp/mixxx-changes.patch
Original file line number Diff line number Diff line change
Expand Up @@ -184,17 +184,45 @@ index 4585ddc..a5b1c12 100644
}
}
diff --git a/lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp b/lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp
index cb8bc24..a4abcbc 100644
index cb8bc24..cc956be 100644
--- a/lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp
+++ b/lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp
@@ -229,6 +229,41 @@ int GetKeyMode::process(double *PCMData)
@@ -70,8 +70,9 @@ GetKeyMode::GetKeyMode( int sampleRate, float tuningFrequency,

// 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 );
- m_ChromaConfig.max = Pitch::getFrequencyForPitch( 96, 0, tuningFrequency );
+ const float centsOffset = -12.0f / kBinsPerOctave * 100; // 3 bins per note, start with the first
+ m_ChromaConfig.min = Pitch::getFrequencyForPitch( 48, centsOffset, tuningFrequency );
+ m_ChromaConfig.max = Pitch::getFrequencyForPitch( 96, centsOffset, tuningFrequency );

m_ChromaConfig.BPO = kBinsPerOctave;
m_ChromaConfig.CQThresh = 0.0054;
@@ -186,14 +187,13 @@ int GetKeyMode::process(double *PCMData)

m_ChrPointer = m_Chroma->process( m_DecimatedBuffer );

-/*
std::cout << "raw chroma: ";
for (int ii = 0; ii < kBinsPerOctave; ++ii) {
if (ii % (kBinsPerOctave/12) == 0) std::cout << "\n";
std::cout << m_ChrPointer[ii] << " ";
}
std::cout << std::endl;
-*/
+
// populate hpcp values;
int cbidx;
for( j = 0; j < kBinsPerOctave; j++ ) {
@@ -229,14 +229,47 @@ int GetKeyMode::process(double *PCMData)
}


+/*
+ // filtered and normalized chromagram
+ for (unsigned int ii = 0; ii < m_BPO; ++ii) {
+ double value = m_MeanHPCP[(ii+m_BPO-1) % m_BPO];
+ double value = m_MeanHPCP[ii];
+ if (value > 0 && maxNoteValue > 0.01) {
+ if (value > 0.99) {
+ std::cout << "Î";
Expand Down Expand Up @@ -224,11 +252,23 @@ index cb8bc24..a4abcbc 100644
+ }
+*/
+
+
+
for( k = 0; k < kBinsPerOctave; k++ )
{
// The Cromagram has the center of C at bin 0, while the major
- // The Cromagram has the center of C at bin 0, while the major
- // and minor profiles have the center of C at 1. We want to have
- // the correlation for C result also at 1.
- // To achieve this we have to shift two times:
- m_MajCorr[k] = krumCorr( m_MeanHPCP, m_MajProfileNorm, (int)k - 2, kBinsPerOctave );
- m_MinCorr[k] = krumCorr( m_MeanHPCP, m_MinProfileNorm, (int)k - 2, kBinsPerOctave );
+ // The cromagram and the major and minor profiles have the has the
+ // center of C at bin 1. We want to have the correlation for C result
+ // also at 1. To achieve this we have to shift by one:
+ m_MajCorr[k] = krumCorr( m_MeanHPCP, m_MajProfileNorm, (int)k - 1, kBinsPerOctave );
+ m_MinCorr[k] = krumCorr( m_MeanHPCP, m_MinProfileNorm, (int)k - 1, kBinsPerOctave );
}

/*
diff --git a/lib/qm-dsp/dsp/transforms/FFT.cpp b/lib/qm-dsp/dsp/transforms/FFT.cpp
index da476b8..6f96b0e 100644
--- a/lib/qm-dsp/dsp/transforms/FFT.cpp
Expand Down Expand Up @@ -270,3 +310,222 @@ index 72e5a57..81d8a8e 100644
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/lib/qm-dsp/mixx-changes.patch b/lib/qm-dsp/mixx-changes.patch
new file mode 100644
index 0000000..1a56a14
--- /dev/null
+++ b/lib/qm-dsp/mixx-changes.patch
@@ -0,0 +1,212 @@
+diff --git a/lib/qm-dsp/dsp/chromagram/ConstantQ.cpp b/lib/qm-dsp/dsp/chromagram/ConstantQ.cpp
+index 4585ddc..a5b1c12 100644
+--- a/lib/qm-dsp/dsp/chromagram/ConstantQ.cpp
++++ b/lib/qm-dsp/dsp/chromagram/ConstantQ.cpp
+@@ -117,31 +117,29 @@ void ConstantQ::sparsekernel()
+
+ FFT m_FFT(m_FFTLength);
+
+- for (unsigned k = m_uK; k--; )
+- {
+- for (unsigned u=0; u < m_FFTLength; u++)
+- {
++ 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)));
++ const double samplesPerCycle =
++ m_FS / (m_FMin * pow(2, (double)k / (double)m_BPO));
+
+-// 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;
+-
++ // Computing a hamming window
++ const unsigned hammingLength = (int) ceil(
++ m_dQ * samplesPerCycle);
+
+ 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<hammingLength; i++) {
++ const double angle = 2*PI*i/samplesPerCycle;
++ 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];
+@@ -152,24 +150,24 @@ void ConstantQ::sparsekernel()
+ 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
+- 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);
+- }
++ //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
++ 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);
++ }
+
+ }
+
+@@ -259,10 +257,9 @@ double* ConstantQ::process( const double* fftdata )
+
+ SparseKernel *sk = m_sparseKernel;
+
+- for (unsigned row=0; row<2*m_uK; row++)
+- {
+- m_CQdata[ row ] = 0;
+- m_CQdata[ row+1 ] = 0;
++ 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]);
+@@ -270,18 +267,19 @@ double* ConstantQ::process( const double* fftdata )
+ 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];
+- if (col == 0) continue;
+- 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);
++ for (unsigned i = 0; i<sparseCells; i++) {
++ 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 ];
++ 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;
+@@ -328,10 +326,9 @@ void ConstantQ::process(const double *FFTRe, const double* FFTIm,
+
+ SparseKernel *sk = m_sparseKernel;
+
+- for (unsigned row=0; row<m_uK; row++)
+- {
+- CQRe[ row ] = 0;
+- CQIm[ row ] = 0;
++ for (unsigned row=0; row<m_uK; row++) {
++ CQRe[ row ] = 0;
++ CQIm[ row ] = 0;
+ }
+
+ const unsigned *fftbin = &(sk->is[0]);
+@@ -340,17 +337,18 @@ void ConstantQ::process(const double *FFTRe, const double* FFTIm,
+ 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];
+- if (col == 0) continue;
+- const double & r1 = real[i];
+- const double & i1 = imag[i];
+- 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);
++ for (unsigned i = 0; i<sparseCells; i++) {
++ 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 ];
++ 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/keydetection/GetKeyMode.cpp b/lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp
+index cb8bc24..cc956be 100644
+--- a/lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp
++++ b/lib/qm-dsp/dsp/keydetection/GetKeyMode.cpp
+@@ -70,8 +70,9 @@ GetKeyMode::GetKeyMode( int sampleRate, float tuningFrequency,
+
+ // 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 );
+- m_ChromaConfig.max = Pitch::getFrequencyForPitch( 96, 0, tuningFrequency );
++ const float centsOffset = -12.0f / kBinsPerOctave * 100; // 3 bins per note, start with the first
++ m_ChromaConfig.min = Pitch::getFrequencyForPitch( 48, centsOffset, tuningFrequency );
++ m_ChromaConfig.max = Pitch::getFrequencyForPitch( 96, centsOffset, tuningFrequency );
+
+ m_ChromaConfig.BPO = kBinsPerOctave;
+ m_ChromaConfig.CQThresh = 0.0054;
+@@ -186,14 +187,13 @@ int GetKeyMode::process(double *PCMData)
+
+ m_ChrPointer = m_Chroma->process( m_DecimatedBuffer );
+
+-/*
+ std::cout << "raw chroma: ";
+ for (int ii = 0; ii < kBinsPerOctave; ++ii) {
+ if (ii % (kBinsPerOctave/12) == 0) std::cout << "\n";
+ std::cout << m_ChrPointer[ii] << " ";
+ }
+ std::cout << std::en
\ No newline at end of file

0 comments on commit 37460c0

Please sign in to comment.