ChordSegmentator.hxx
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef ChordSegmentator_hxx
00023 #define ChordSegmentator_hxx
00024
00025 #include <iostream>
00026 #include <fstream>
00027 #include <cmath>
00028 #include "Array.hxx"
00029 #include "DiscontinuousSegmentation.hxx"
00030 #include "ChordCorrelator.hxx"
00031 #include "Assert.hxx"
00032
00033 namespace Simac
00034 {
00035
00044 class ChordSegmentator
00045 {
00046 CLAM::DiscontinuousSegmentation _segmentation;
00047 std::vector<unsigned> _chordIndexes;
00048
00049 unsigned _currentSegment;
00050 bool _segmentOpen;
00051 unsigned _lastChord;
00052
00053 unsigned _method;
00054
00055
00056 std::vector< std::vector<double> > _chordSimilarity;
00057 std::vector<double> _segmentChordCorrelation;
00058 unsigned _framesInSegment;
00059 public:
00060 ChordSegmentator()
00061 : _segmentation(0)
00062 , _currentSegment(0)
00063 , _segmentOpen(false)
00064 , _lastChord(0)
00065 , _framesInSegment(0)
00066 {
00067 method(0);
00068 };
00069 ~ChordSegmentator() {};
00070
00071 void doIt(CLAM::TData & currentTime, const std::vector<double> & correlation, const unsigned firstCandidate, const unsigned secondCandidate)
00072 {
00073 _segmentation.maxPosition(currentTime);
00074 switch(_method)
00075 {
00076 case 2:
00077 doItSimilarity(currentTime, correlation, firstCandidate, secondCandidate);
00078 break;
00079 default:
00080 doItSimple(currentTime, correlation, firstCandidate, secondCandidate);
00081 }
00082 }
00083
00087 void doItSimple(CLAM::TData & currentTime, const std::vector<double> & correlation, const unsigned firstCandidate, const unsigned secondCandidate)
00088 {
00089 CLAM::TData firstCandidateWeight = correlation[firstCandidate];
00090 CLAM::TData noCandidateWeight = correlation[0];
00091
00092 unsigned currentChord = firstCandidateWeight*0.6<=noCandidateWeight || noCandidateWeight<0.001 ?
00093 0 : firstCandidate;
00094
00095 if(_segmentOpen)
00096 {
00097 if(!currentChord)
00098 closeSegment(currentTime);
00099 if(currentChord != _lastChord)
00100 closeSegment(currentTime);
00101 }
00102 if(!_segmentOpen)
00103 {
00104 if(currentChord)
00105 openSegment(currentTime, currentChord);
00106 }
00107
00108 _lastChord = currentChord;
00109
00110 if(_segmentOpen)
00111 _segmentation.dragOffset(_currentSegment, currentTime);
00112 }
00113
00117 void doItSimilarity(CLAM::TData & currentTime, const std::vector<double> & correlation, const unsigned firstCandidate, const unsigned secondCandidate)
00118 {
00119 CLAM::TData firstCandidateWeight = correlation[firstCandidate];
00120 CLAM::TData noCandidateWeight = correlation[0];
00121
00122 unsigned currentChord = firstCandidateWeight*0.6<=noCandidateWeight || noCandidateWeight<0.001 ?
00123 0 : firstCandidate;
00124
00125 unsigned segmentChord=0;
00126
00127 if(_segmentOpen)
00128 {
00129 for(unsigned i=0; i<correlation.size(); i++)
00130 _segmentChordCorrelation[i] += correlation[i]/correlation[0];
00131 _framesInSegment++;
00132 estimateChord(_segmentChordCorrelation, segmentChord);
00133 _chordIndexes[_currentSegment] = segmentChord;
00134
00135 double segmentCorrelationDiffNew = (_segmentChordCorrelation[segmentChord] - _segmentChordCorrelation[currentChord]) / _framesInSegment;
00136
00137 double similarity = _chordSimilarity[currentChord][segmentChord];
00138
00139 double similarityThreshold = 0.67;
00140 double correlationThreshold = 0.3;
00141
00142 if(!currentChord)
00143 {
00144 closeSegment(currentTime);
00145 _framesInSegment = 0;
00146 for(unsigned i=0; i<correlation.size(); i++)
00147 _segmentChordCorrelation[i] = 0;
00148 }
00149
00150 if (similarity < similarityThreshold)
00151 {
00152 if(segmentCorrelationDiffNew > correlationThreshold)
00153 {
00154 closeSegment(currentTime);
00155 _framesInSegment = 0;
00156 for(unsigned i=0; i<correlation.size(); i++)
00157 _segmentChordCorrelation[i] = 0;
00158 }
00159 }
00160
00161 }
00162 if(!_segmentOpen && currentChord)
00163 {
00164 openSegment(currentTime, currentChord);
00165 for(unsigned i=0; i<correlation.size(); i++)
00166 _segmentChordCorrelation[i] = correlation[i]/correlation[0];
00167 _framesInSegment++;
00168 segmentChord=currentChord;
00169 }
00170
00171 if(_segmentOpen)
00172 _segmentation.dragOffset(_currentSegment, currentTime);
00173 }
00174
00175 void openSegment(CLAM::TData & currentTime, unsigned currentChord)
00176 {
00177 _chordIndexes.push_back(currentChord);
00178 _currentSegment = _segmentation.insert(currentTime);
00179 _segmentOpen = true;
00180 }
00181 void closeSegment(CLAM::TData & currentTime)
00182 {
00183 _segmentation.dragOffset(_currentSegment, currentTime);
00184 _segmentOpen = false;
00185
00186 switch(_method)
00187 {
00188 case 1:
00189 changeChordIfSegmentTooSmall(_currentSegment);
00190 break;
00191 case 2:
00192 changeChordIfSegmentTooSmall(_currentSegment);
00193 break;
00194 }
00195
00196 mergeSegmentIfIdenticalChordInPreviousSegment(_currentSegment);
00197 }
00198
00199 void changeChordIfSegmentTooSmall(unsigned & segment)
00200 {
00201 double minSegmentLength = 0.5;
00202
00203 std::vector<double> onsets = _segmentation.onsets();
00204 std::vector<double> offsets = _segmentation.offsets();
00205 unsigned lastSegment = onsets.size();
00206 CLAM_ASSERT(segment<lastSegment, "changeChordIfSegmentTooSmall: Accessing a segment beyond lastSegment");
00207
00208 if(offsets[segment]-onsets[segment] < minSegmentLength)
00209 {
00210 if(segment<lastSegment)
00211 if(offsets[segment]==onsets[segment+1])
00212 _chordIndexes[segment] = _chordIndexes[segment+1];
00213 if(segment>0)
00214 if(onsets[segment]==offsets[segment-1])
00215 _chordIndexes[segment] = _chordIndexes[segment-1];
00216 }
00217 }
00218 void mergeSegmentIfIdenticalChordInPreviousSegment(unsigned & segment)
00219 {
00220 CLAM::TData time = _segmentation.offsets()[segment];
00221 if(segment>0)
00222 {
00223 if(_chordIndexes[segment] == _chordIndexes[segment-1]
00224 && _segmentation.onsets()[segment] == _segmentation.offsets()[segment-1])
00225 {
00226 _segmentation.remove(segment);
00227 _chordIndexes.erase(_chordIndexes.begin()+segment);
00228 segment--;
00229 _segmentation.dragOffset(segment, time);
00230 }
00231 }
00232 }
00233
00234 void closeLastSegment(CLAM::TData & currentTime )
00235 {
00236 _segmentation.maxPosition(currentTime);
00237
00238 if (_lastChord != 0)
00239 {
00240 _segmentation.dragOffset(_currentSegment, currentTime);
00241 _segmentOpen = false;
00242 }
00243
00244 switch(_method)
00245 {
00246 case 1:
00247 changeChordsForSmallSegments();
00248 joinSegmentsWithIdenticalChords();
00249 break;
00250 }
00251 }
00252
00253 void eraseAllSegments()
00254 {
00255 while( _segmentation.onsets().size() )
00256 {
00257 _segmentation.remove(_segmentation.onsets().size()-1);
00258 _chordIndexes.pop_back();
00259 }
00260 _segmentation.maxPosition(0);
00261 }
00262
00263 void estimateChord(const ChordCorrelator::ChordCorrelation & correlation, unsigned & estimatedChord)
00264 {
00265 double maxCorrelation = 0;
00266 double underMaxCorrelation = 0;
00267 unsigned maxIndex = 0;
00268 unsigned underMaxIndex = 0;
00269 for (unsigned i=0; i<correlation.size(); i++)
00270 {
00271 if (correlation[i]<underMaxCorrelation) continue;
00272 if (correlation[i]<maxCorrelation)
00273 {
00274 underMaxIndex=i;
00275 underMaxCorrelation=correlation[i];
00276 continue;
00277 }
00278 underMaxIndex=maxIndex;
00279 underMaxCorrelation=maxCorrelation;
00280 maxIndex=i;
00281 maxCorrelation=correlation[i];
00282 }
00283 estimatedChord = maxIndex;
00284 }
00285
00286
00287
00288
00289
00295 void changeChordsForSmallSegments()
00296 {
00297 for(unsigned segment=0; segment<_segmentation.onsets().size(); segment++)
00298 changeChordIfSegmentTooSmall(segment);
00299 }
00300 void joinSegmentsWithIdenticalChords()
00301 {
00302 for(unsigned segment=1; segment<_segmentation.onsets().size(); segment++)
00303 mergeSegmentIfIdenticalChordInPreviousSegment(segment);
00304 }
00305
00306 const CLAM::DiscontinuousSegmentation & segmentation() const { return _segmentation; };
00307 const std::vector<unsigned> & chordIndexes() const { return _chordIndexes; };
00308 void method(unsigned method)
00309 {
00310 _method=method;
00311 if(method != 0 && method != 1 && method != 2)
00312 _method = 0;
00313
00314 switch(_method)
00315 {
00316 case 2:
00317 ChordCorrelator chordCorrelator;
00318 _chordSimilarity = chordCorrelator.chordPatternsSimilarity();
00319 for(unsigned i=0; i<101; ++i)
00320 _segmentChordCorrelation.push_back(0);
00321 break;
00322 }
00323 }
00324 };
00325 }
00326 #endif//ChordSegmentator