CLAM-Development  1.4.0
ChordSegmentator.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2006 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 #ifndef ChordSegmentator_hxx
23 #define ChordSegmentator_hxx
24 
25 #include <iostream>
26 #include <fstream>
27 #include <cmath>
28 #include "Array.hxx"
30 #include "ChordCorrelator.hxx"
31 #include "Assert.hxx"
32 
33 namespace Simac
34 {
35 
45 {
46  CLAM::DiscontinuousSegmentation _segmentation;
47  std::vector<unsigned> _chordIndexes;
48 
49  unsigned _currentSegment;
50  bool _segmentOpen;
51  unsigned _lastChord;
52 
53  unsigned _method;
54 
55  // Chord similarity method variables
56  std::vector< std::vector<double> > _chordSimilarity;
57  std::vector<double> _segmentChordCorrelation;
58  unsigned _framesInSegment;
59 public:
61  : _segmentation(0)
62  , _currentSegment(0)
63  , _segmentOpen(false)
64  , _lastChord(0)
65  , _framesInSegment(0)
66  {
67  method(0);
68  };
70 
71  void doIt(CLAM::TData & currentTime, const std::vector<double> & correlation, const unsigned firstCandidate, const unsigned secondCandidate)
72  {
73  _segmentation.maxPosition(currentTime);
74  switch(_method)
75  {
76  case 2:
77  doItSimilarity(currentTime, correlation, firstCandidate, secondCandidate);
78  break;
79  default:
80  doItSimple(currentTime, correlation, firstCandidate, secondCandidate);
81  }
82  }
83 
87  void doItSimple(CLAM::TData & currentTime, const std::vector<double> & correlation, const unsigned firstCandidate, const unsigned secondCandidate)
88  {
89  CLAM::TData firstCandidateWeight = correlation[firstCandidate];
90  CLAM::TData noCandidateWeight = correlation[0];
91 
92  unsigned currentChord = firstCandidateWeight*0.6<=noCandidateWeight || noCandidateWeight<0.001 ?
93  0 : firstCandidate;
94 
95  if(_segmentOpen)
96  {
97  if(!currentChord)
98  closeSegment(currentTime);
99  if(currentChord != _lastChord)
100  closeSegment(currentTime);
101  }
102  if(!_segmentOpen)
103  {
104  if(currentChord)
105  openSegment(currentTime, currentChord);
106  }
107 
108  _lastChord = currentChord;
109 
110  if(_segmentOpen)
111  _segmentation.dragOffset(_currentSegment, currentTime);
112  }
113 
117  void doItSimilarity(CLAM::TData & currentTime, const std::vector<double> & correlation, const unsigned firstCandidate, const unsigned secondCandidate)
118  {
119  CLAM::TData firstCandidateWeight = correlation[firstCandidate];
120  CLAM::TData noCandidateWeight = correlation[0];
121 
122  unsigned currentChord = firstCandidateWeight*0.6<=noCandidateWeight || noCandidateWeight<0.001 ?
123  0 : firstCandidate;
124 
125  unsigned segmentChord=0;
126 
127  if(_segmentOpen)
128  {
129  for(unsigned i=0; i<correlation.size(); i++)
130  _segmentChordCorrelation[i] += correlation[i]/correlation[0];
131  _framesInSegment++;
132  estimateChord(_segmentChordCorrelation, segmentChord);
133  _chordIndexes[_currentSegment] = segmentChord;
134 
135  double segmentCorrelationDiffNew = (_segmentChordCorrelation[segmentChord] - _segmentChordCorrelation[currentChord]) / _framesInSegment;
136 
137  double similarity = _chordSimilarity[currentChord][segmentChord];
138 
139  double similarityThreshold = 0.67;
140  double correlationThreshold = 0.3;
141 
142  if(!currentChord)
143  {
144  closeSegment(currentTime);
145  _framesInSegment = 0;
146  for(unsigned i=0; i<correlation.size(); i++)
147  _segmentChordCorrelation[i] = 0;
148  }
149 
150  if (similarity < similarityThreshold)
151  {
152  if(segmentCorrelationDiffNew > correlationThreshold)
153  {
154  closeSegment(currentTime);
155  _framesInSegment = 0;
156  for(unsigned i=0; i<correlation.size(); i++)
157  _segmentChordCorrelation[i] = 0;
158  }
159  }
160 
161  }
162  if(!_segmentOpen && currentChord)
163  {
164  openSegment(currentTime, currentChord);
165  for(unsigned i=0; i<correlation.size(); i++)
166  _segmentChordCorrelation[i] = correlation[i]/correlation[0];
167  _framesInSegment++;
168  segmentChord=currentChord;
169  }
170 
171  if(_segmentOpen)
172  _segmentation.dragOffset(_currentSegment, currentTime);
173  }
174 
175  void openSegment(CLAM::TData & currentTime, unsigned currentChord)
176  {
177  _chordIndexes.push_back(currentChord);
178  _currentSegment = _segmentation.insert(currentTime);
179  _segmentOpen = true;
180  }
181  void closeSegment(CLAM::TData & currentTime)
182  {
183  _segmentation.dragOffset(_currentSegment, currentTime);
184  _segmentOpen = false;
185 
186  switch(_method)
187  {
188  case 1:
189  changeChordIfSegmentTooSmall(_currentSegment);
190  break;
191  case 2:
192  changeChordIfSegmentTooSmall(_currentSegment);
193  break;
194  }
195 
197  }
198 
199  void changeChordIfSegmentTooSmall(unsigned & segment)
200  {
201  double minSegmentLength = 0.5;
202 
203  std::vector<double> onsets = _segmentation.onsets();
204  std::vector<double> offsets = _segmentation.offsets();
205  unsigned lastSegment = onsets.size();
206  CLAM_ASSERT(segment<lastSegment, "changeChordIfSegmentTooSmall: Accessing a segment beyond lastSegment");
207 
208  if(offsets[segment]-onsets[segment] < minSegmentLength)
209  {
210  if(segment<lastSegment)
211  if(offsets[segment]==onsets[segment+1])
212  _chordIndexes[segment] = _chordIndexes[segment+1];
213  if(segment>0)
214  if(onsets[segment]==offsets[segment-1])
215  _chordIndexes[segment] = _chordIndexes[segment-1];
216  }
217  }
219  {
220  CLAM::TData time = _segmentation.offsets()[segment];
221  if(segment>0)
222  {
223  if(_chordIndexes[segment] == _chordIndexes[segment-1]
224  && _segmentation.onsets()[segment] == _segmentation.offsets()[segment-1])
225  {
226  _segmentation.remove(segment);
227  _chordIndexes.erase(_chordIndexes.begin()+segment);
228  segment--;
229  _segmentation.dragOffset(segment, time);
230  }
231  }
232  }
233 
234  void closeLastSegment(CLAM::TData & currentTime )
235  {
236  _segmentation.maxPosition(currentTime);
237 
238  if (_lastChord != 0)
239  {
240  _segmentation.dragOffset(_currentSegment, currentTime);
241  _segmentOpen = false;
242  }
243 
244  switch(_method)
245  {
246  case 1:
249  break;
250  }
251  }
252 
254  {
255  while( _segmentation.onsets().size() )
256  {
257  _segmentation.remove(_segmentation.onsets().size()-1);
258  _chordIndexes.pop_back();
259  }
260  _segmentation.maxPosition(0);
261  }
262 
263  void estimateChord(const ChordCorrelator::ChordCorrelation & correlation, unsigned & estimatedChord)
264  {
265  double maxCorrelation = 0;
266  double underMaxCorrelation = 0;
267  unsigned maxIndex = 0;
268  unsigned underMaxIndex = 0;
269  for (unsigned i=0; i<correlation.size(); i++)
270  {
271  if (correlation[i]<underMaxCorrelation) continue;
272  if (correlation[i]<maxCorrelation)
273  {
274  underMaxIndex=i;
275  underMaxCorrelation=correlation[i];
276  continue;
277  }
278  underMaxIndex=maxIndex;
279  underMaxCorrelation=maxCorrelation;
280  maxIndex=i;
281  maxCorrelation=correlation[i];
282  }
283  estimatedChord = maxIndex;
284  }
285 
286  //
287  // Post Processing Functions
288  //
289 
296  {
297  for(unsigned segment=0; segment<_segmentation.onsets().size(); segment++)
299  }
301  {
302  for(unsigned segment=1; segment<_segmentation.onsets().size(); segment++)
304  }
305 
306  const CLAM::DiscontinuousSegmentation & segmentation() const { return _segmentation; };
307  const std::vector<unsigned> & chordIndexes() const { return _chordIndexes; };
308  void method(unsigned method)
309  {
310  _method=method;
311  if(method != 0 && method != 1 && method != 2)
312  _method = 0;
313 
314  switch(_method)
315  {
316  case 2:
317  ChordCorrelator chordCorrelator;
318  _chordSimilarity = chordCorrelator.chordPatternsSimilarity();
319  for(unsigned i=0; i<101; ++i)
320  _segmentChordCorrelation.push_back(0);
321  break;
322  }
323  }
324 };
325 }
326 #endif//ChordSegmentator