|
CLAM-Development
1.3
|
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 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 // Chord similarity method variables 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 // Post Processing Functions 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
1.7.6.1