00001 #include "Transcriber.h"
00002 #include <iostream>
00003
00004 namespace Marsyas
00005 {
00006
00007
00008 #define MIN_NOTE_FRAMES 9
00009
00010
00011
00012
00013
00014 Transcriber::Transcriber()
00015 {
00016 }
00017
00018 Transcriber::~Transcriber()
00019 {
00020 }
00021
00022
00023 mrs_real
00024 Transcriber::findMedianWithoutZeros(const mrs_natural start,
00025 const mrs_natural length,
00026 const realvec& array)
00027 {
00028 if ( length<=0 )
00029 return 0;
00030 realvec noZeros;
00031 noZeros.create(length);
00032 mrs_natural j=0;
00033
00034 for (mrs_natural i=0; i<length; ++i)
00035 {
00036 if ( array(start+i) > 0 )
00037 {
00038 noZeros(j)=array(start+i);
00039 j++;
00040 }
00041 }
00042 noZeros.stretch(j-1);
00043 if (j-1 <= 0)
00044 return 0;
00045 return noZeros.median();
00046 }
00047
00048 realvec
00049 Transcriber::findPeaks(const realvec& list, const mrs_real cutoff)
00050 {
00051 realvec peaks(1);
00052 mrs_natural valIndex = 0;
00053
00054 mrs_real localMax;
00055 mrs_natural minSpace = MIN_NOTE_FRAMES;
00056 mrs_natural prevValIndex = 0;
00057 mrs_real prevValValue = 1.0;
00058 for (mrs_natural i=minSpace; i<list.getSize()-minSpace; ++i)
00059 {
00060 if ( (list(i) > list(i-1)) &&
00061 (list(i) > list(i+1)) &&
00062 (list(i) > cutoff) )
00063 {
00064 localMax = list(i);
00065 if ((mrs_natural)i < prevValIndex+minSpace)
00066 {
00067 if (localMax > prevValValue)
00068 {
00069
00070 peaks(valIndex-1) = i;
00071 prevValIndex = i;
00072 prevValValue = localMax;
00073 }
00074 }
00075 else
00076 {
00077
00078 peaks.stretchWrite(valIndex, i);
00079 valIndex++;
00080 prevValIndex = i;
00081 prevValValue = localMax;
00082 }
00083 }
00084 }
00085 peaks.stretch(valIndex);
00086 return peaks;
00087 }
00088
00089 realvec
00090 Transcriber::findValleys(const realvec& list)
00091 {
00092 realvec valleys(1);
00093 mrs_natural valIndex = 0;
00094
00095 mrs_real localMin;
00096 mrs_natural minSpace = MIN_NOTE_FRAMES;
00097 mrs_natural prevValIndex = 0;
00098 mrs_real prevValValue = 1.0;
00099 for (mrs_natural i=minSpace; i<list.getSize()-minSpace; ++i)
00100 {
00101 if ( (list(i) < list(i-1)) &&
00102 (list(i) < list(i+1)))
00103 {
00104 localMin = list(i);
00105 if ((mrs_natural)i < prevValIndex+minSpace)
00106 {
00107 if (localMin < prevValValue)
00108 {
00109
00110 valleys(valIndex-1) = i;
00111 prevValIndex = i;
00112 prevValValue = localMin;
00113 }
00114 }
00115 else
00116 {
00117
00118 valleys.stretchWrite(valIndex, i);
00119 valIndex++;
00120 prevValIndex = i;
00121 prevValValue = localMin;
00122 }
00123 }
00124 }
00125 valleys.stretch(valIndex);
00126 return valleys;
00127 }
00128
00129 mrs_real
00130 Transcriber::findNextPeakValue(const realvec& list, const mrs_natural
00131 start)
00132 {
00133 mrs_natural i = start;
00134 mrs_bool isPeak = false;
00135 mrs_real minValue = 0.1;
00136 do
00137 {
00138 ++i;
00139 if (i == list.getSize())
00140 return 0.0;
00141 if ( (list(i) > list(i-1)) &&
00142 (list(i) > list(i+1)) &&
00143 ( list(i) > minValue) )
00144 {
00145 isPeak = true;
00146 }
00147 }
00148 while ( isPeak == false );
00149 return list(i);
00150 }
00151
00152
00153
00154
00155
00156 void
00157 Transcriber::pitchSegment(const realvec& pitchList, realvec&
00158 boundaries, const mrs_natural width)
00159 {
00160 if (boundaries.getSize() == 0)
00161 {
00162 boundaries.create(2);
00163 boundaries(0) = 0.0;
00164 boundaries(1) = pitchList.getSize();
00165 }
00166 realvec region, *newBoundaries, regionBounds;
00167 mrs_natural start, length;
00168 newBoundaries = new realvec;
00169 for (mrs_natural i=0; i<boundaries.getSize()-1; ++i)
00170 {
00171 start = (mrs_natural) boundaries(i);
00172 length = (mrs_natural) (boundaries(i+1) - boundaries(i));
00173 region = pitchList.getSubVector(start, length);
00174 regionBounds = findPitchBoundaries(region, width);
00175 regionBounds += start;
00176 newBoundaries->appendRealvec(regionBounds);
00177 }
00178 boundaries.appendRealvec(*newBoundaries);
00179 boundaries.sort();
00180 }
00181
00182 realvec
00183 Transcriber::findPitchBoundaries(const realvec& pitchList, const
00184 mrs_natural width)
00185 {
00186
00187 mrs_natural minSpace = width;
00188 mrs_real noteBoundary = 0.5;
00189
00190 realvec boundaries(1);
00191 mrs_natural onsetIndex=0;
00192
00193 mrs_real median;
00194 mrs_real prevNote=0.0;
00195 mrs_natural prevSamp=0;
00196 for (mrs_natural i=minSpace; i<pitchList.getSize()-minSpace; ++i)
00197 {
00198 median = findMedianWithoutZeros(i-minSpace, 2*minSpace, pitchList);
00199 if ( fabs(median-prevNote) > noteBoundary )
00200 {
00201 if ((mrs_natural)i > prevSamp+minSpace)
00202 {
00203 prevNote = median;
00204 prevSamp = i;
00205 boundaries.stretchWrite( onsetIndex, i);
00206 onsetIndex++;
00207 }
00208 else
00209 {
00210 prevNote = median;
00211 }
00212 }
00213 }
00214 boundaries.stretch(onsetIndex);
00215 return boundaries;
00216 }
00217
00218
00219
00220
00221 void
00222 Transcriber::ampSegment(const realvec& ampList, realvec&
00223 boundaries, const mrs_real cutoff)
00224 {
00225 if (boundaries.getSize() == 0)
00226 {
00227 boundaries.create(2);
00228 boundaries(0) = 0.0;
00229 boundaries(1) = ampList.getSize()-1;
00230 }
00231 realvec region, *newBoundaries, regionBounds;
00232 mrs_natural start, length;
00233 newBoundaries = new realvec;
00234 for (mrs_natural i=0; i<boundaries.getSize()-1; ++i)
00235 {
00236 start = (mrs_natural) boundaries(i);
00237 length = (mrs_natural) (boundaries(i+1) - boundaries(i));
00238 region = ampList.getSubVector(start, length);
00239
00240 regionBounds = findPeaks(region, cutoff);
00241
00242 regionBounds += start;
00243 newBoundaries->appendRealvec(regionBounds);
00244 }
00245 boundaries.appendRealvec(*newBoundaries);
00246 boundaries.sort();
00247 }
00248
00249 void
00250 Transcriber::filterAmpBoundaries(realvec& regionAmps, realvec ®ionBounds)
00251 {
00252 if (regionBounds.getSize() < 2)
00253 return;
00254
00255
00256 mrs_natural numSamples = regionBounds.getSize();
00257 realvec newBounds(numSamples);
00258 mrs_natural newIndex=0;
00259
00260 mrs_real regionMinVal = 0.1;
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 regionAmps /= regionAmps.maxval();
00273
00274 mrs_natural start, length;
00275 mrs_real valleyMinVal = 0.20;
00276 mrs_real valley;
00277 realvec region;
00278 for (mrs_natural i=0; i<regionBounds.getSize(); ++i)
00279 {
00280 start = (mrs_natural) regionBounds(i);
00281 if (i < regionBounds.getSize()-1 )
00282 length = (mrs_natural) (regionBounds(i+1) - regionBounds(i));
00283 else
00284 length = regionAmps.getSize() - i;
00285 region = regionAmps.getSubVector(start, length);
00286
00287 valley = regionAmps(start);
00288 if ( (valley < valleyMinVal) &&
00289
00290 (region.mean() > regionMinVal) )
00291 {
00292
00293 newBounds(newIndex) = start;
00294 newIndex++;
00295 }
00296 else
00297 {
00298
00299
00300
00301 }
00302 }
00303 newBounds.stretch(newIndex);
00304
00305
00306 regionBounds = newBounds;
00307 }
00308
00309
00310
00311
00312 void
00313 Transcriber::getRelativeDurations(const realvec& boundaries, realvec
00314 &durations)
00315 {
00316 mrs_natural numNotes = boundaries.getSize()-1;
00317 durations.create(numNotes);
00318
00319 mrs_natural i;
00320 mrs_natural min = 99999;
00321
00322
00323 for (i=0; i<numNotes; ++i)
00324 {
00325 durations(i) = boundaries(i+1) - boundaries(i);
00326
00327
00328 if (durations(i) < min)
00329 min = (mrs_natural) durations(i);
00330 }
00331
00332
00333
00334 for (i=0; i<numNotes; ++i)
00335 {
00336 durations(i) = (mrs_natural) ( durations(i) / (min) );
00337 }
00338 }
00339
00340 void
00341 Transcriber::discardBeginEndSilences(const realvec& pitchList, const realvec&
00342 ampList, realvec& boundaries)
00343 {
00344
00345 (void) ampList;
00346
00347 mrs_real notePitch;
00348 mrs_natural i,j;
00349 mrs_natural start,length;
00350
00351 i=0;
00352 start = (mrs_natural) boundaries(i);
00353 length = (mrs_natural) ( boundaries(i+1)-boundaries(i) );
00354 notePitch = findMedianWithoutZeros(start, length, pitchList);
00355 while ( (notePitch == 0) && (i < boundaries.getSize()-1) )
00356 {
00357 for (j=i; j<boundaries.getSize()-1; j++)
00358 boundaries(j) = boundaries(j+1);
00359 boundaries.stretch(j);
00360 ++i;
00361 start = (mrs_natural) boundaries(i);
00362 length = (mrs_natural) ( boundaries(i+1)-boundaries(i) );
00363 notePitch = findMedianWithoutZeros(start, length, pitchList);
00364 }
00365
00366 i=boundaries.getSize()-2;
00367 start = (mrs_natural) boundaries(i);
00368 length = (mrs_natural) ( boundaries(i+1)-boundaries(i) );
00369 notePitch = findMedianWithoutZeros(start, length, pitchList);
00370 while ( (notePitch == 0) && (i < boundaries.getSize()-1) )
00371 {
00372 boundaries.stretch(i+1);
00373 i--;
00374 start = (mrs_natural) boundaries(i);
00375 length = (mrs_natural) ( boundaries(i+1)-boundaries(i) );
00376 notePitch = findMedianWithoutZeros(start, length, pitchList);
00377 }
00378 }
00379
00380 void
00381 Transcriber::discardEndingTotalSilenceAmpsOnly(realvec& ampList)
00382 {
00383 mrs_natural i = ampList.getSize()-1;
00384
00385 while ( (i>0) && (ampList(i) == 0.0))
00386 {
00387 i--;
00388 }
00389 ampList.stretch(i);
00390 }
00391
00392 void
00393 Transcriber::discardBeginEndSilencesAmpsOnly(const realvec& ampList,
00394 realvec& boundaries)
00395 {
00396 mrs_real sampleAmp;
00397 mrs_natural i,j;
00398 i=0;
00399
00400 mrs_natural start = (mrs_natural) boundaries(i);
00401 mrs_natural length = (mrs_natural) ( boundaries(i+1)-boundaries(i) );
00402 sampleAmp = ampList(start);
00403 while ( (sampleAmp < 0.1) && (i < boundaries.getSize()-1) )
00404 {
00405 for (j=i; j<boundaries.getSize()-1; j++)
00406 boundaries(j) = boundaries(j+1);
00407 boundaries.stretch(j);
00408 ++i;
00409 start = (mrs_natural) boundaries(i);
00410 length = (mrs_natural) ( boundaries(i+1)-boundaries(i) );
00411 sampleAmp = ampList(start);
00412 }
00413
00414 i=boundaries.getSize()-2;
00415 start = (mrs_natural) boundaries(i);
00416 length = (mrs_natural) ( boundaries(i+1)-boundaries(i) );
00417 sampleAmp = ampList(start);
00418 while ( (sampleAmp < 0.1) && (i < boundaries.getSize()-1) )
00419 {
00420 boundaries.stretch(i+1);
00421 i--;
00422 start = (mrs_natural) boundaries(i);
00423 length = (mrs_natural) ( boundaries(i+1)-boundaries(i) );
00424 sampleAmp = ampList(start);
00425 }
00426 }
00427
00428
00429
00430 realvec
00431 Transcriber::getNotes(const realvec& pitchList, const realvec& ampList,
00432 const realvec& boundaries)
00433 {
00434 mrs_natural numNotes = boundaries.getSize()-1;
00435 realvec notes(numNotes, 2);
00436
00437 mrs_natural start, length;
00438 mrs_real notePitch;
00439
00440 mrs_natural boundIndex = 0;
00441 notePitch = findMedianWithoutZeros(0, (mrs_natural) boundaries(1),
00442 pitchList);
00443 if (notePitch == 0)
00444 boundIndex++;
00445 mrs_natural firstFrame = (mrs_natural) boundaries(boundIndex);
00446 for (mrs_natural i=0; i<numNotes; ++i)
00447 {
00448 notes(i,1) = boundaries(boundIndex) - firstFrame;
00449
00450
00451 start = (mrs_natural) boundaries(boundIndex);
00452 length = (mrs_natural) (boundaries(boundIndex+1) -
00453 boundaries(boundIndex));
00454 notePitch = findMedianWithoutZeros(start, length, pitchList);
00455
00456 notes(i,0) = notePitch;
00457 boundIndex++;
00458 }
00459 notes.stretch(boundIndex-2,2);
00460 return notes;
00461 }
00462
00463 }
00464