ChordSegmentator.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 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
Generated by  doxygen 1.6.3