Mercurial > hg > silvet
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(); |
