CLAM-Development  1.4.0
ChordExtractor.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2006 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 #ifndef ChordExtractor_hxx
23 #define ChordExtractor_hxx
24 
26 #include "ChordSegmentator.hxx"
27 #include "ChordCorrelator.hxx"
28 #include "CircularPeakPicking.hxx"
29 #include "CircularPeaksToPCP.hxx"
30 #include "CircularPeakTunner.hxx"
31 #include "ConstantQFolder.hxx"
32 #include "ConstantQTransform.hxx"
33 #include "FourierTransform.hxx"
35 #include "SemitoneCenterFinder.hxx"
36 #include "PCPSmother.hxx"
37 
38 namespace Simac
39 {
40 
42 {
43  double _sparseConstantQKernelThreshold;
44  ConstantQTransform _constantQTransform;
45  ConstantQFolder _constantQFolder;
46  FourierTransform _fourierTransform;
47  CircularPeakPicking _circularPeakPicking;
48  InstantTunningEstimator _instantTunningEstimator;
49  CircularPeakTunner _circularPeakTunner;
50  CircularPeaksToPCP _circularPeaksToPCP;
51  PCPSmother _filter;
52  ChordCorrelator _chordCorrelator;
53  ChordSegmentator _chordSegmentator;
54  bool _tunningEnabled;
55  bool _peakWindowingEnabled;
56  double _hopRatio;
57  unsigned _estimatedChord;
58  unsigned _secondCandidate;
59  double _squaredRootEnergy;
60 public:
61  static double maximumFrequency(double sampleRate) { return sampleRate/2.1; } // Just below nyquist
62  typedef float * AudioFrame;
63 
64  ChordExtractor(unsigned sampleRate=44100, double minimumFrequency=98, unsigned binsPerOctave=36)
65  : _sparseConstantQKernelThreshold(0.0054)
66  , _constantQTransform(sampleRate, minimumFrequency, maximumFrequency(sampleRate), binsPerOctave)
67  , _constantQFolder(_constantQTransform.getK(), binsPerOctave)
68  , _fourierTransform(_constantQTransform.getfftlength(),1,0)
69  , _circularPeakPicking(binsPerOctave, /*scaling factor*/ 12.0/binsPerOctave)
70  , _instantTunningEstimator(/*Inertia*/ 1.0)
71  , _circularPeakTunner(/*reference tunning*/ 0.0)
72  , _filter(0.7)
73  , _tunningEnabled(true)
74  , _peakWindowingEnabled(true)
75  , _hopRatio(8.0) // On the original Chromagram cpp code was 32
76  , _estimatedChord(0)
77  , _secondCandidate(0)
78  {
79  _constantQTransform.sparsekernel(_sparseConstantQKernelThreshold);
80  if (_peakWindowingEnabled)
81  _circularPeaksToPCP.activateWindowing();
82  }
84  {
85  }
86 
87  // Accessors
88  void filterInertia(double inertia)
89  {
90  _filter.inertia(inertia);
91  }
92  void enableTunning(bool tunningEnabled=true) { _tunningEnabled=tunningEnabled; }
93  void enablePeakWindowing(bool peakWindowingEnabled=true) { _peakWindowingEnabled=peakWindowingEnabled; }
94  void hopRatio(double hopRatio) { _hopRatio=hopRatio; }
95  void segmentationMethod(double segmentationMethod) { _chordSegmentator.method(segmentationMethod); }
96 
97  unsigned hop() const {return _constantQTransform.getfftlength()/_hopRatio;}
98  unsigned frameSize() const {return _constantQTransform.getfftlength();}
99 
100  void doIt(const AudioFrame & input, CLAM::TData & currentTime)
101  {
102  _squaredRootEnergy = 0.0;
103  for (unsigned i=0; i<frameSize(); i++)
104  _squaredRootEnergy += input[i]*input[i];
105 
106  _fourierTransform.doIt(input);
107  _constantQTransform.doIt(_fourierTransform.spectrum());
108  _constantQFolder.doIt(_constantQTransform.constantQSpectrum());
109  _circularPeakPicking.doIt(_constantQFolder.chromagram());
110  _instantTunningEstimator.doIt(_circularPeakPicking.output());
111  _circularPeakTunner.doIt(_instantTunningEstimator.output().first, _circularPeakPicking.output());
112  if (_tunningEnabled)
113  _circularPeaksToPCP.doIt(_circularPeakTunner.output());
114  else
115  _circularPeaksToPCP.doIt(_circularPeakPicking.output());
116  _filter.doIt(_circularPeaksToPCP.output());
117  _chordCorrelator.doIt(_filter.output());
118  estimateChord(_chordCorrelator.output());
119  _chordSegmentator.doIt(currentTime, _chordCorrelator.output(), _estimatedChord, _secondCandidate);
120  }
122  {
123  double maxCorrelation = 0;
124  double underMaxCorrelation = 0;
125  unsigned maxIndex = 0;
126  unsigned underMaxIndex = 0;
127  for (unsigned i=0; i<correlation.size(); i++)
128  {
129  if (correlation[i]<underMaxCorrelation) continue;
130  if (correlation[i]<maxCorrelation)
131  {
132  underMaxIndex=i;
133  underMaxCorrelation=correlation[i];
134  continue;
135  }
136  underMaxIndex=maxIndex;
137  underMaxCorrelation=maxCorrelation;
138  maxIndex=i;
139  maxCorrelation=correlation[i];
140  }
141  _estimatedChord = maxIndex;
142  _secondCandidate = underMaxIndex;
143  }
144  std::string chordRepresentation(unsigned chordIndex) const
145  {
146  return _chordCorrelator.chordRepresentation(chordIndex);
147  }
148  std::string root(unsigned chordIndex) const
149  {
150  return _chordCorrelator.root(chordIndex);
151  }
152  std::string mode(unsigned chordIndex) const
153  {
154  return _chordCorrelator.mode(chordIndex);
155  }
156  const std::string chordEstimation() const
157  {
158  const ChordCorrelator::ChordCorrelation & correlation = _chordCorrelator.output();
159  double maxCorrelation=correlation[_estimatedChord];
160  double underMaxCorrelation=correlation[_secondCandidate];
161  if (maxCorrelation*0.7<=correlation[0]) return "None";
162  bool estimationIsClear = maxCorrelation*0.9>underMaxCorrelation;
163  std::ostringstream os;
164  os << _chordCorrelator.chordRepresentation(_estimatedChord);
165  if (!estimationIsClear)
166  os << " [or "<< _chordCorrelator.chordRepresentation(_secondCandidate)<< "]";
167  os << " (" << (correlation[0]/maxCorrelation) << ")";
168  if (!estimationIsClear)
169  os << " (" << (underMaxCorrelation/(underMaxCorrelation+maxCorrelation)) << ")";
170  return os.str();
171  }
172  const std::vector<double> & chromagram() const
173  {
174  return _constantQFolder.chromagram();
175  }
176  const std::vector<double> & pcp() const
177  {
178  return _circularPeaksToPCP.output();
179  }
180  const std::vector<std::pair<double, double> > & peaks() const
181  {
182  return _circularPeakPicking.output();
183  }
184  const std::vector<double> & chordCorrelation() const
185  {
186  return _chordCorrelator.output();
187  }
189  {
190  return _chordSegmentator.segmentation();
191  }
192  const std::vector<unsigned> & chordIndexes() const
193  {
194  return _chordSegmentator.chordIndexes();
195  }
196  void clear()
197  {
198  _chordSegmentator.eraseAllSegments();
199  }
200  void closeLastSegment(CLAM::TData currentTime)
201  {
202  _chordSegmentator.closeLastSegment(currentTime);
203  }
204  double tunning() const {return _instantTunningEstimator.output().first; }
205  double tunningStrength() const {return _instantTunningEstimator.output().second; }
206  std::pair<double,double> instantTunning() const {return _instantTunningEstimator.instantTunning(); }
207  double energy() const {return _squaredRootEnergy; }
208  unsigned firstCandidate() const {return _estimatedChord;}
209  unsigned secondCandidate() const {return _secondCandidate;}
210  std::vector<double> spectrum() const {return _fourierTransform.spectrum(); }
211 
212 };
213 }
214 
215 #endif//ChordExtractor
216