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
00207 if(offsets[segment]-onsets[segment] < minSegmentLength)
00208 {
00209 if(segment<lastSegment)
00210 if(offsets[segment]==onsets[segment+1])
00211 _chordIndexes[segment] = _chordIndexes[segment+1];
00212 if(segment>0)
00213 if(onsets[segment]==offsets[segment-1])
00214 _chordIndexes[segment] = _chordIndexes[segment-1];
00215 }
00216 }
00217 void mergeSegmentIfIdenticalChordInPreviousSegment(unsigned & segment)
00218 {
00219 CLAM::TData time = _segmentation.offsets()[segment];
00220 if(segment>0)
00221 {
00222 if(_chordIndexes[segment] == _chordIndexes[segment-1]
00223 && _segmentation.onsets()[segment] == _segmentation.offsets()[segment-1])
00224 {
00225 _segmentation.remove(segment);
00226 _chordIndexes.erase(_chordIndexes.begin()+segment);
00227 segment--;
00228 _segmentation.dragOffset(segment, time);
00229 }
00230 }
00231 }
00232
00233 void closeLastSegment(CLAM::TData & currentTime )
00234 {
00235 _segmentation.maxPosition(currentTime);
00236
00237 if (_lastChord != 0)
00238 {
00239 _segmentation.dragOffset(_currentSegment, currentTime);
00240 _segmentOpen = false;
00241 }
00242
00243 switch(_method)
00244 {
00245 case 1:
00246 changeChordsForSmallSegments();
00247 joinSegmentsWithIdenticalChords();
00248 break;
00249 }
00250 }
00251
00252 void eraseAllSegments()
00253 {
00254 while( _segmentation.onsets().size() )
00255 {
00256 _segmentation.remove(_segmentation.onsets().size()-1);
00257 _chordIndexes.pop_back();
00258 }
00259 _segmentation.maxPosition(0);
00260 }
00261
00262 void estimateChord(const ChordCorrelator::ChordCorrelation & correlation, unsigned & estimatedChord)
00263 {
00264 double maxCorrelation = 0;
00265 double underMaxCorrelation = 0;
00266 unsigned maxIndex = 0;
00267 unsigned underMaxIndex = 0;
00268 for (unsigned i=0; i<correlation.size(); i++)
00269 {
00270 if (correlation[i]<underMaxCorrelation) continue;
00271 if (correlation[i]<maxCorrelation)
00272 {
00273 underMaxIndex=i;
00274 underMaxCorrelation=correlation[i];
00275 continue;
00276 }
00277 underMaxIndex=maxIndex;
00278 underMaxCorrelation=maxCorrelation;
00279 maxIndex=i;
00280 maxCorrelation=correlation[i];
00281 }
00282 estimatedChord = maxIndex;
00283 }
00284
00285
00286
00287
00288
00294 void changeChordsForSmallSegments()
00295 {
00296 for(unsigned segment=0; segment<_segmentation.onsets().size(); segment++)
00297 changeChordIfSegmentTooSmall(segment);
00298 }
00299 void joinSegmentsWithIdenticalChords()
00300 {
00301 for(unsigned segment=1; segment<_segmentation.onsets().size(); segment++)
00302 mergeSegmentIfIdenticalChordInPreviousSegment(segment);
00303 }
00304
00305 const CLAM::DiscontinuousSegmentation & segmentation() const { return _segmentation; };
00306 const std::vector<unsigned> & chordIndexes() const { return _chordIndexes; };
00307 void method(unsigned method)
00308 {
00309 _method=method;
00310 if(method != 0 && method != 1 && method != 2)
00311 _method = 0;
00312
00313 switch(_method)
00314 {
00315 case 2:
00316 ChordCorrelator chordCorrelator;
00317 _chordSimilarity = chordCorrelator.chordPatternsSimilarity();
00318 for(unsigned i=0; i<101; ++i)
00319 _segmentChordCorrelation.push_back(0);
00320 break;
00321 }
00322 }
00323 };
00324 }
00325 #endif//ChordSegmentator