ChordExtractor.hxx

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001-2006 MUSIC TECHNOLOGY GROUP (MTG)
00003  *                         UNIVERSITAT POMPEU FABRA
00004  *
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 
00022 #ifndef ChordExtractor_hxx
00023 #define ChordExtractor_hxx
00024 
00025 #include "DiscontinuousSegmentation.hxx"
00026 #include "ChordSegmentator.hxx"
00027 #include "ChordCorrelator.hxx"
00028 #include "CircularPeakPicking.hxx"
00029 #include "CircularPeaksToPCP.hxx"
00030 #include "CircularPeakTunner.hxx"
00031 #include "ConstantQFolder.hxx"
00032 #include "ConstantQTransform.hxx"
00033 #include "FourierTransform.hxx"
00034 #include "InstantTunningEstimator.hxx"
00035 #include "SemitoneCenterFinder.hxx"
00036 #include "PCPSmother.hxx"
00037 
00038 namespace Simac
00039 {
00040 
00041 class ChordExtractor
00042 {
00043         double _sparseConstantQKernelThreshold;
00044         ConstantQTransform _constantQTransform;
00045         ConstantQFolder _constantQFolder;
00046         FourierTransform _fourierTransform;
00047         CircularPeakPicking _circularPeakPicking;
00048         InstantTunningEstimator _instantTunningEstimator;
00049         CircularPeakTunner _circularPeakTunner;
00050         CircularPeaksToPCP _circularPeaksToPCP;
00051         PCPSmother _filter;
00052         ChordCorrelator _chordCorrelator;
00053         ChordSegmentator _chordSegmentator;
00054         bool _tunningEnabled;
00055         bool _peakWindowingEnabled;
00056         double _hopRatio;
00057         unsigned _estimatedChord;
00058         unsigned _secondCandidate;
00059         double _squaredRootEnergy;
00060 public:
00061         static double maximumFrequency(double sampleRate) { return sampleRate/2.1; } // Just below nyquist
00062         typedef float * AudioFrame;
00063 
00064         ChordExtractor(unsigned sampleRate=44100, double minimumFrequency=98, unsigned binsPerOctave=36)
00065                 : _sparseConstantQKernelThreshold(0.0054)
00066                 , _constantQTransform(sampleRate, minimumFrequency, maximumFrequency(sampleRate), binsPerOctave)
00067                 , _constantQFolder(_constantQTransform.getK(), binsPerOctave)
00068                 , _fourierTransform(_constantQTransform.getfftlength(),1,0)
00069                 , _circularPeakPicking(binsPerOctave, /*scaling factor*/ 12.0/binsPerOctave)
00070                 , _instantTunningEstimator(/*Inertia*/ 1.0)
00071                 , _circularPeakTunner(/*reference tunning*/ 0.0)
00072                 , _filter(0.7)
00073                 , _tunningEnabled(true)
00074                 , _peakWindowingEnabled(true)
00075                 , _hopRatio(8.0) // On the original Chromagram cpp code was 32
00076                 , _estimatedChord(0)
00077                 , _secondCandidate(0)
00078         {
00079                 _constantQTransform.sparsekernel(_sparseConstantQKernelThreshold);
00080                 if (_peakWindowingEnabled)
00081                         _circularPeaksToPCP.activateWindowing();
00082         }
00083         ~ChordExtractor()
00084         {
00085         }
00086 
00087         // Accessors
00088         void filterInertia(double inertia)
00089         {
00090                 _filter.inertia(inertia);
00091         }
00092         void enableTunning(bool tunningEnabled=true)  { _tunningEnabled=tunningEnabled; }
00093         void enablePeakWindowing(bool peakWindowingEnabled=true)  { _peakWindowingEnabled=peakWindowingEnabled; }
00094         void hopRatio(double hopRatio) { _hopRatio=hopRatio; }
00095         void segmentationMethod(double segmentationMethod) { _chordSegmentator.method(segmentationMethod); }
00096 
00097         unsigned hop() const {return _constantQTransform.getfftlength()/_hopRatio;}
00098         unsigned frameSize() const {return _constantQTransform.getfftlength();}
00099 
00100         void doIt(const AudioFrame & input, CLAM::TData & currentTime)
00101         {
00102                 _squaredRootEnergy = 0.0;
00103                 for (unsigned i=0; i<frameSize(); i++)
00104                         _squaredRootEnergy += input[i]*input[i];
00105                         
00106                 _fourierTransform.doIt(input);
00107                 _constantQTransform.doIt(_fourierTransform.spectrum());
00108                 _constantQFolder.doIt(_constantQTransform.constantQSpectrum());
00109                 _circularPeakPicking.doIt(_constantQFolder.chromagram());
00110                 _instantTunningEstimator.doIt(_circularPeakPicking.output());
00111                 _circularPeakTunner.doIt(_instantTunningEstimator.output().first, _circularPeakPicking.output());
00112                 if (_tunningEnabled)
00113                         _circularPeaksToPCP.doIt(_circularPeakTunner.output());
00114                 else
00115                         _circularPeaksToPCP.doIt(_circularPeakPicking.output());
00116                 _filter.doIt(_circularPeaksToPCP.output());
00117                 _chordCorrelator.doIt(_filter.output());
00118                 estimateChord(_chordCorrelator.output());
00119                 _chordSegmentator.doIt(currentTime, _chordCorrelator.output(), _estimatedChord, _secondCandidate);
00120         }
00121         void estimateChord(const ChordCorrelator::ChordCorrelation & correlation)
00122         {
00123                 double maxCorrelation = 0;
00124                 double underMaxCorrelation = 0;
00125                 unsigned maxIndex = 0;
00126                 unsigned underMaxIndex = 0;
00127                 for (unsigned i=0; i<correlation.size(); i++)
00128                 {
00129                         if (correlation[i]<underMaxCorrelation) continue;
00130                         if (correlation[i]<maxCorrelation)
00131                         {
00132                                 underMaxIndex=i;
00133                                 underMaxCorrelation=correlation[i];
00134                                 continue;
00135                         }
00136                         underMaxIndex=maxIndex;
00137                         underMaxCorrelation=maxCorrelation;
00138                         maxIndex=i;
00139                         maxCorrelation=correlation[i];
00140                 }
00141                 _estimatedChord = maxIndex;
00142                 _secondCandidate = underMaxIndex;
00143         }
00144         std::string chordRepresentation(unsigned chordIndex) const
00145         {
00146                 return _chordCorrelator.chordRepresentation(chordIndex);
00147         }
00148         std::string root(unsigned chordIndex) const
00149         {
00150                 return _chordCorrelator.root(chordIndex);
00151         }
00152         std::string mode(unsigned chordIndex) const
00153         {
00154                 return _chordCorrelator.mode(chordIndex);
00155         }
00156         const std::string chordEstimation() const
00157         {
00158                 const ChordCorrelator::ChordCorrelation & correlation = _chordCorrelator.output();
00159                 double maxCorrelation=correlation[_estimatedChord];
00160                 double underMaxCorrelation=correlation[_secondCandidate];
00161                 if (maxCorrelation*0.7<=correlation[0]) return "None";
00162                 bool estimationIsClear = maxCorrelation*0.9>underMaxCorrelation;
00163                 std::ostringstream os;
00164                 os << _chordCorrelator.chordRepresentation(_estimatedChord);
00165                 if (!estimationIsClear) 
00166                         os << " [or "<< _chordCorrelator.chordRepresentation(_secondCandidate)<< "]";
00167                 os << " (" << (correlation[0]/maxCorrelation) << ")";
00168                 if (!estimationIsClear) 
00169                         os << " (" << (underMaxCorrelation/(underMaxCorrelation+maxCorrelation)) << ")";
00170                 return os.str();
00171         }
00172         const std::vector<double> & chromagram() const
00173         {
00174                 return _constantQFolder.chromagram();
00175         }
00176         const std::vector<double> & pcp() const
00177         {
00178                 return _circularPeaksToPCP.output();
00179         }
00180         const std::vector<std::pair<double, double> > & peaks() const
00181         {
00182                 return _circularPeakPicking.output();
00183         }
00184         const std::vector<double> & chordCorrelation() const
00185         {
00186                 return _chordCorrelator.output();
00187         }
00188         const CLAM::DiscontinuousSegmentation & segmentation() const
00189         {
00190                 return _chordSegmentator.segmentation();
00191         }
00192         const std::vector<unsigned> & chordIndexes() const
00193         {
00194                 return _chordSegmentator.chordIndexes();
00195         }
00196         void clear()
00197         {
00198                 _chordSegmentator.eraseAllSegments();
00199         }
00200         void closeLastSegment(CLAM::TData currentTime)
00201         {
00202                 _chordSegmentator.closeLastSegment(currentTime);
00203         }
00204         double tunning() const {return _instantTunningEstimator.output().first; }
00205         double tunningStrength() const {return _instantTunningEstimator.output().second; }
00206         std::pair<double,double> instantTunning() const {return _instantTunningEstimator.instantTunning(); }
00207         double energy() const {return _squaredRootEnergy; }
00208         unsigned firstCandidate() const {return _estimatedChord;}
00209         unsigned secondCandidate() const {return _secondCandidate;}
00210         std::vector<double> spectrum() const {return _fourierTransform.spectrum(); }
00211 
00212 };
00213 }
00214 
00215 #endif//ChordExtractor
00216 
Generated by  doxygen 1.6.3