comparison src/Silvet.cpp @ 165:f73be84f5c90

Use 20ms resolution in hq mode, 40ms only in draft mode
author Chris Cannam
date Tue, 20 May 2014 16:48:33 +0100
parents 629c9525b815
children 7979fa40c9f7
comparison
equal deleted inserted replaced
164:629c9525b815 165:f73be84f5c90
140 desc.minValue = 0; 140 desc.minValue = 0;
141 desc.maxValue = 1; 141 desc.maxValue = 1;
142 desc.defaultValue = 1; 142 desc.defaultValue = 1;
143 desc.isQuantized = true; 143 desc.isQuantized = true;
144 desc.quantizeStep = 1; 144 desc.quantizeStep = 1;
145 desc.valueNames.push_back("Draft: faster"); 145 desc.valueNames.push_back("Draft (faster)");
146 desc.valueNames.push_back("Intensive: usually higher quality"); 146 desc.valueNames.push_back("Intensive (higher quality)");
147 list.push_back(desc); 147 list.push_back(desc);
148 148
149 desc.identifier = "soloinstrument"; 149 desc.identifier = "soloinstrument";
150 desc.name = "Instrument in recording"; 150 desc.name = "Solo instrument";
151 desc.unit = ""; 151 desc.unit = "";
152 desc.description = "The instrument known to be present in the recording, if there is only one"; 152 desc.description = "The instrument known to be present in the recording, if there is only one";
153 desc.minValue = 0; 153 desc.minValue = 0;
154 desc.maxValue = m_instruments.size()-1; 154 desc.maxValue = m_instruments.size()-1;
155 desc.defaultValue = 0; 155 desc.defaultValue = 0;
297 params.threshold = 0.0005; 297 params.threshold = 0.0005;
298 params.window = CQParameters::Hann; //!!! todo: test whether it makes any difference 298 params.window = CQParameters::Hann; //!!! todo: test whether it makes any difference
299 299
300 m_cq = new CQSpectrogram(params, CQSpectrogram::InterpolateLinear); 300 m_cq = new CQSpectrogram(params, CQSpectrogram::InterpolateLinear);
301 301
302 m_colsPerSec = m_hqMode ? 50 : 25;
303
302 for (int i = 0; i < (int)m_postFilter.size(); ++i) { 304 for (int i = 0; i < (int)m_postFilter.size(); ++i) {
303 delete m_postFilter[i]; 305 delete m_postFilter[i];
304 } 306 }
305 m_postFilter.clear(); 307 m_postFilter.clear();
306 for (int i = 0; i < processingNotes; ++i) { 308 for (int i = 0; i < processingNotes; ++i) {
307 m_postFilter.push_back(new MedianFilter<double>(3)); 309 m_postFilter.push_back(new MedianFilter<double>(3));
308 } 310 }
309 m_pianoRoll.clear(); 311 m_pianoRoll.clear();
310 m_columnCount = 0; 312 m_columnCount = 0;
311 m_reducedColumnCount = 0;
312 m_startTime = RealTime::zeroTime; 313 m_startTime = RealTime::zeroTime;
313 } 314 }
314 315
315 Silvet::FeatureSet 316 Silvet::FeatureSet
316 Silvet::process(const float *const *inputBuffers, Vamp::RealTime timestamp) 317 Silvet::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
395 Silvet::Grid 396 Silvet::Grid
396 Silvet::preProcess(const Grid &in) 397 Silvet::preProcess(const Grid &in)
397 { 398 {
398 int width = in.size(); 399 int width = in.size();
399 400
400 // reduce to 100 columns per second, or one column every 441 samples 401 int spacing = processingSampleRate / m_colsPerSec;
401 402
402 int spacing = processingSampleRate / 100; 403 // need to be careful that col spacing is an integer number of samples!
404 assert(spacing * m_colsPerSec == processingSampleRate);
403 405
404 Grid out; 406 Grid out;
405 407
406 // We count the CQ latency in terms of processing hops, but 408 // We count the CQ latency in terms of processing hops, but
407 // actually it probably isn't an exact number of hops so this 409 // actually it probably isn't an exact number of hops so this
408 // isn't quite accurate. But the small constant offset is 410 // isn't quite accurate. But the small constant offset is
409 // practically irrelevant compared to the jitter from the 40ms 411 // practically irrelevant compared to the jitter from the frame
410 // frame size we reduce to in a moment 412 // size we reduce to in a moment
411 int latentColumns = m_cq->getLatency() / m_cq->getColumnHop(); 413 int latentColumns = m_cq->getLatency() / m_cq->getColumnHop();
412 414
413 for (int i = 0; i < width; ++i) { 415 for (int i = 0; i < width; ++i) {
414 416
415 if (m_columnCount < latentColumns) { 417 if (m_columnCount < latentColumns) {
447 MedianFilter<double>::filter(40, noiseLevel1); 449 MedianFilter<double>::filter(40, noiseLevel1);
448 for (int j = 0; j < processingHeight; ++j) { 450 for (int j = 0; j < processingHeight; ++j) {
449 outCol[j] = std::max(outCol[j] - noiseLevel2[j], 0.0); 451 outCol[j] = std::max(outCol[j] - noiseLevel2[j], 0.0);
450 } 452 }
451 453
452 // then we only use every fourth filtered column, for 25 454 out.push_back(outCol);
453 // columns per second in the eventual grid
454
455 if (m_reducedColumnCount % 4 == 0) {
456 out.push_back(outCol);
457 }
458
459 ++m_reducedColumnCount;
460 } 455 }
461 456
462 ++m_columnCount; 457 ++m_columnCount;
463 } 458 }
464 459
509 // already, and if they haven't ended, we don't know their 504 // already, and if they haven't ended, we don't know their
510 // duration. 505 // duration.
511 506
512 int width = m_pianoRoll.size(); 507 int width = m_pianoRoll.size();
513 508
514 //!!! adjust to only keep notes >= 100ms? or so 509 double columnDuration = 1.0 / m_colsPerSec;
515 int durationThreshold = 3; // columns 510
511 // only keep notes >= 100ms or thereabouts
512 int durationThreshold = floor(0.1 / columnDuration); // columns
513 if (durationThreshold < 1) durationThreshold = 1;
516 514
517 FeatureList noteFeatures; 515 FeatureList noteFeatures;
518 516
519 if (width < durationThreshold + 1) { 517 if (width < durationThreshold + 1) {
520 m_pianoRoll.push_back(active); 518 m_pianoRoll.push_back(active);
521 return noteFeatures; 519 return noteFeatures;
522 } 520 }
523
524 // we have 25 columns per second
525 double columnDuration = 1.0 / 25.0;
526 521
527 //!!! try: 20ms intervals in intensive mode 522 //!!! try: 20ms intervals in intensive mode
528 //!!! try: repeated note detection? (look for change in first derivative of the pitch matrix) 523 //!!! try: repeated note detection? (look for change in first derivative of the pitch matrix)
529 524
530 for (map<int, double>::const_iterator ni = m_pianoRoll[width-1].begin(); 525 for (map<int, double>::const_iterator ni = m_pianoRoll[width-1].begin();