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