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 
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         // Post Processing Functions
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

Generated on Tue Aug 12 22:33:42 2008 for CLAM by  doxygen 1.5.5