annotate dsp/chromagram/Chromagram.cpp @ 468:a72d98f8baa3

Revise mechanism for extending chromagram to round number of octaves - do it only in the chromagram itself, so that we can still create deviant constant-Q spectrograms if desired
author Chris Cannam <cannam@all-day-breakfast.com>
date Thu, 30 May 2019 11:35:35 +0100
parents 1db23b9a8da4
children fdaa63607c15
rev   line source
c@225 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@225 2
c@225 3 /*
c@225 4 QM DSP Library
c@225 5
c@225 6 Centre for Digital Music, Queen Mary, University of London.
c@309 7 This file 2005-2006 Christian Landone.
c@309 8
c@309 9 This program is free software; you can redistribute it and/or
c@309 10 modify it under the terms of the GNU General Public License as
c@309 11 published by the Free Software Foundation; either version 2 of the
c@309 12 License, or (at your option) any later version. See the file
c@309 13 COPYING included with this distribution for more information.
c@225 14 */
c@225 15
c@225 16 #include <iostream>
c@225 17 #include <cmath>
c@241 18 #include "maths/MathUtilities.h"
c@225 19 #include "Chromagram.h"
c@225 20
c@225 21 //----------------------------------------------------------------------------
c@225 22
c@276 23 Chromagram::Chromagram( ChromaConfig Config ) :
c@276 24 m_skGenerated(false)
c@225 25 {
c@225 26 initialise( Config );
c@225 27 }
c@225 28
c@225 29 int Chromagram::initialise( ChromaConfig Config )
c@225 30 {
c@225 31 m_FMin = Config.min; // min freq
c@225 32 m_FMax = Config.max; // max freq
c@225 33 m_BPO = Config.BPO; // bins per octave
c@259 34 m_normalise = Config.normalise; // if frame normalisation is required
c@225 35
cannam@468 36 // Extend range to a full octave
cannam@468 37 double octaves = log(m_FMax / m_FMin) / log(2.0);
cannam@468 38 m_FMax = m_FMin * pow(2.0, ceil(octaves));
c@225 39
c@225 40 // Create array for chroma result
c@225 41 m_chromadata = new double[ m_BPO ];
c@225 42
c@225 43 // Create Config Structure for ConstantQ operator
c@225 44 CQConfig ConstantQConfig;
c@225 45
c@225 46 // Populate CQ config structure with parameters
c@225 47 // inherited from the Chroma config
cannam@465 48 ConstantQConfig.FS = Config.FS;
c@225 49 ConstantQConfig.min = m_FMin;
c@225 50 ConstantQConfig.max = m_FMax;
c@225 51 ConstantQConfig.BPO = m_BPO;
c@225 52 ConstantQConfig.CQThresh = Config.CQThresh;
c@225 53
c@225 54 // Initialise ConstantQ operator
c@225 55 m_ConstantQ = new ConstantQ( ConstantQConfig );
c@225 56
cannam@468 57 // No. of constant Q bins
cannam@468 58 m_uK = m_ConstantQ->getK();
cannam@468 59
c@225 60 // Initialise working arrays
c@225 61 m_frameSize = m_ConstantQ->getfftlength();
c@225 62 m_hopSize = m_ConstantQ->gethop();
c@225 63
c@289 64 // Initialise FFT object
c@289 65 m_FFT = new FFTReal(m_frameSize);
c@289 66
c@225 67 m_FFTRe = new double[ m_frameSize ];
c@225 68 m_FFTIm = new double[ m_frameSize ];
c@225 69 m_CQRe = new double[ m_uK ];
c@225 70 m_CQIm = new double[ m_uK ];
c@225 71
c@257 72 m_window = 0;
c@257 73 m_windowbuf = 0;
c@257 74
c@225 75 return 1;
c@225 76 }
c@225 77
c@225 78 Chromagram::~Chromagram()
c@225 79 {
c@225 80 deInitialise();
c@225 81 }
c@225 82
c@225 83 int Chromagram::deInitialise()
c@225 84 {
c@257 85 delete[] m_windowbuf;
c@257 86 delete m_window;
c@257 87
c@225 88 delete [] m_chromadata;
c@225 89
c@225 90 delete m_FFT;
c@225 91
c@225 92 delete m_ConstantQ;
c@225 93
c@225 94 delete [] m_FFTRe;
c@225 95 delete [] m_FFTIm;
c@225 96 delete [] m_CQRe;
c@225 97 delete [] m_CQIm;
c@225 98 return 1;
c@225 99 }
c@225 100
c@225 101 //----------------------------------------------------------------------------------
c@225 102 // returns the absolute value of complex number xx + i*yy
c@225 103 double Chromagram::kabs(double xx, double yy)
c@225 104 {
c@225 105 double ab = sqrt(xx*xx + yy*yy);
c@225 106 return(ab);
c@225 107 }
c@225 108 //-----------------------------------------------------------------------------------
c@225 109
c@225 110
c@225 111 void Chromagram::unityNormalise(double *src)
c@225 112 {
c@225 113 double min, max;
c@225 114
c@225 115 double val = 0;
c@225 116
c@225 117 MathUtilities::getFrameMinMax( src, m_BPO, & min, &max );
c@225 118
c@414 119 for (int i = 0; i < m_BPO; i++)
c@225 120 {
c@225 121 val = src[ i ] / max;
c@225 122
c@225 123 src[ i ] = val;
c@225 124 }
c@225 125 }
c@225 126
c@225 127
cannam@467 128 double *Chromagram::process(const double *data)
c@225 129 {
c@276 130 if (!m_skGenerated) {
c@276 131 // Generate CQ Kernel
c@276 132 m_ConstantQ->sparsekernel();
c@276 133 m_skGenerated = true;
c@276 134 }
c@276 135
c@257 136 if (!m_window) {
c@257 137 m_window = new Window<double>(HammingWindow, m_frameSize);
c@257 138 m_windowbuf = new double[m_frameSize];
c@257 139 }
c@257 140
c@257 141 for (int i = 0; i < m_frameSize; ++i) {
c@257 142 m_windowbuf[i] = data[i];
c@257 143 }
c@257 144 m_window->cut(m_windowbuf);
c@257 145
cannam@467 146 // The frequency-domain version expects pre-fftshifted input - so
cannam@467 147 // we must do the same here
cannam@467 148 for (int i = 0; i < m_frameSize/2; ++i) {
cannam@467 149 double tmp = m_windowbuf[i];
cannam@467 150 m_windowbuf[i] = m_windowbuf[i + m_frameSize/2];
cannam@467 151 m_windowbuf[i + m_frameSize/2] = tmp;
cannam@467 152 }
cannam@467 153
c@339 154 m_FFT->forward(m_windowbuf, m_FFTRe, m_FFTIm);
c@228 155
c@228 156 return process(m_FFTRe, m_FFTIm);
c@228 157 }
c@228 158
cannam@467 159 double *Chromagram::process(const double *real, const double *imag)
c@228 160 {
c@276 161 if (!m_skGenerated) {
c@276 162 // Generate CQ Kernel
c@276 163 m_ConstantQ->sparsekernel();
c@276 164 m_skGenerated = true;
c@276 165 }
c@276 166
c@228 167 // initialise chromadata to 0
c@414 168 for (int i = 0; i < m_BPO; i++) m_chromadata[i] = 0;
c@225 169
c@225 170 // Calculate ConstantQ frame
c@228 171 m_ConstantQ->process( real, imag, m_CQRe, m_CQIm );
c@225 172
c@225 173 // add each octave of cq data into Chromagram
cannam@466 174 const int octaves = m_uK / m_BPO;
cannam@466 175 for (int octave = 0; octave < octaves; octave++)
c@225 176 {
c@414 177 int firstBin = octave*m_BPO;
c@414 178 for (int i = 0; i < m_BPO; i++)
c@225 179 {
c@225 180 m_chromadata[i] += kabs( m_CQRe[ firstBin + i ], m_CQIm[ firstBin + i ]);
c@225 181 }
c@225 182 }
c@225 183
c@259 184 MathUtilities::normalise(m_chromadata, m_BPO, m_normalise);
c@225 185
c@225 186 return m_chromadata;
c@225 187 }
c@225 188
c@225 189