Mercurial > hg > silvet
comparison src/Silvet.cpp @ 168:51bd3d833db8 finetune
Store active shifts separately from active pitches
author | Chris Cannam |
---|---|
date | Wed, 21 May 2014 09:11:49 +0100 |
parents | 416b555df3b2 |
children | 192c4ba3de45 |
comparison
equal
deleted
inserted
replaced
167:416b555df3b2 | 168:51bd3d833db8 |
---|---|
261 | 261 |
262 return buf; | 262 return buf; |
263 } | 263 } |
264 | 264 |
265 float | 265 float |
266 Silvet::noteFrequency(int note, int shiftCount) const | 266 Silvet::noteFrequency(int note, int shift, int shiftCount) const |
267 { | 267 { |
268 float fineNote = float(note) / float(shiftCount); | 268 float fineNote = float(note) + float(shift) / float(shiftCount); |
269 return float(27.5 * pow(2.0, fineNote / 12.0)); | 269 return float(27.5 * pow(2.0, fineNote / 12.0)); |
270 } | 270 } |
271 | 271 |
272 bool | 272 bool |
273 Silvet::initialise(size_t channels, size_t stepSize, size_t blockSize) | 273 Silvet::initialise(size_t channels, size_t stepSize, size_t blockSize) |
390 em[i]->iterate(filtered.at(i).data()); | 390 em[i]->iterate(filtered.at(i).data()); |
391 } | 391 } |
392 } | 392 } |
393 | 393 |
394 int shiftCount = 1; | 394 int shiftCount = 1; |
395 | |
395 if (m_hqMode && m_fineTuning) { | 396 if (m_hqMode && m_fineTuning) { |
396 shiftCount = m_instruments[m_instrument].templateMaxShift * 2 + 1; | 397 shiftCount = m_instruments[m_instrument].templateMaxShift * 2 + 1; |
397 } | 398 } |
398 | 399 |
399 for (int i = 0; i < width; ++i) { | 400 for (int i = 0; i < width; ++i) { |
400 | 401 |
401 if (!em[i]) { | 402 if (!em[i]) { |
402 noteTrack(map<int, double>(), shiftCount); | 403 m_pianoRoll.push_back(map<int, double>()); |
404 if (shiftCount > 1) { | |
405 m_pianoRollShifts.push_back(map<int, int>()); | |
406 } | |
403 continue; | 407 continue; |
404 } | 408 } |
405 | 409 |
406 map<int, double> active = postProcess(em[i]->getPitchDistribution(), | 410 postProcess(em[i]->getPitchDistribution(), |
407 em[i]->getShifts(), | 411 em[i]->getShifts(), |
408 shiftCount, | 412 shiftCount, |
409 sums[i]); | 413 sums[i]); |
410 | 414 |
411 delete em[i]; | 415 delete em[i]; |
412 | 416 |
413 FeatureList noteFeatures = noteTrack(active, shiftCount); | 417 FeatureList noteFeatures = noteTrack(shiftCount); |
414 | 418 |
415 for (FeatureList::const_iterator fi = noteFeatures.begin(); | 419 for (FeatureList::const_iterator fi = noteFeatures.begin(); |
416 fi != noteFeatures.end(); ++fi) { | 420 fi != noteFeatures.end(); ++fi) { |
417 fs[m_notesOutputNo].push_back(*fi); | 421 fs[m_notesOutputNo].push_back(*fi); |
418 } | 422 } |
486 } | 490 } |
487 | 491 |
488 return out; | 492 return out; |
489 } | 493 } |
490 | 494 |
491 map<int, double> | 495 void |
492 Silvet::postProcess(const float *pitches, | 496 Silvet::postProcess(const float *pitches, |
493 const float *const *shifts, | 497 const float *const *shifts, |
494 int shiftCount, | 498 int shiftCount, |
495 double gain) | 499 double gain) |
496 { | 500 { |
516 for (int j = 0; j < processingNotes; ++j) { | 520 for (int j = 0; j < processingNotes; ++j) { |
517 | 521 |
518 double strength = filtered[j]; | 522 double strength = filtered[j]; |
519 if (strength < threshold) continue; | 523 if (strength < threshold) continue; |
520 | 524 |
521 // convert note number j to a pitch value p. If we are not | 525 strengths.insert(ValueIndexMap::value_type(strength, j)); |
522 // using fine tuning, p is the same as j; otherwise p is j * | 526 } |
523 // shiftCount + preferred shift | 527 |
524 | 528 ValueIndexMap::const_iterator si = strengths.end(); |
525 int p = j; | 529 |
526 | 530 map<int, double> active; |
527 if (m_hqMode && m_fineTuning && shiftCount > 1) { | 531 map<int, int> activeShifts; |
532 | |
533 while (int(active.size()) < polyphony && si != strengths.begin()) { | |
534 | |
535 --si; | |
536 | |
537 double strength = si->first; | |
538 int j = si->second; | |
539 | |
540 active[j] = strength; | |
541 | |
542 if (shiftCount > 1) { | |
543 | |
544 // find preferred shift f for note j | |
545 int bestShift = 0; | |
546 | |
528 float bestShiftValue = 0.f; | 547 float bestShiftValue = 0.f; |
529 int bestShift = 0; | |
530 for (int f = 0; f < shiftCount; ++f) { | 548 for (int f = 0; f < shiftCount; ++f) { |
531 if (f == 0 || shifts[f][j] > bestShiftValue) { | 549 if (f == 0 || shifts[f][j] > bestShiftValue) { |
532 bestShiftValue = shifts[f][j]; | 550 bestShiftValue = shifts[f][j]; |
533 bestShift = f; | 551 bestShift = f - int(shiftCount / 2); |
534 } | 552 } |
535 } | 553 } |
536 //!!! I think our shift array per note is actually upside down, check this | 554 //!!! I think our shift array per note is actually upside down, check this |
537 p = j * shiftCount + bestShift; | 555 |
538 } | 556 activeShifts[j] = bestShift; |
539 | 557 } |
540 strengths.insert(ValueIndexMap::value_type(strength, p)); | 558 } |
541 } | 559 |
542 | 560 m_pianoRoll.push_back(active); |
543 map<int, double> active; | 561 if (shiftCount > 1) { |
544 ValueIndexMap::const_iterator si = strengths.end(); | 562 m_pianoRollShifts.push_back(activeShifts); |
545 while (int(active.size()) < polyphony && si != strengths.begin()) { | 563 } |
546 --si; | |
547 // cerr << si->second << " : " << si->first << endl; | |
548 active[si->second] = si->first; | |
549 if (si == strengths.begin()) break; | |
550 } | |
551 | |
552 return active; | |
553 } | 564 } |
554 | 565 |
555 Vamp::Plugin::FeatureList | 566 Vamp::Plugin::FeatureList |
556 Silvet::noteTrack(const map<int, double> &active, int shiftCount) | 567 Silvet::noteTrack(int shiftCount) |
557 { | 568 { |
558 // Minimum duration pruning, and conversion to notes. We can only | 569 // Minimum duration pruning, and conversion to notes. We can only |
559 // report notes that have just ended (i.e. that are absent in the | 570 // report notes that have just ended (i.e. that are absent in the |
560 // latest active set but present in the last set in the piano | 571 // latest active set but present in the prior set in the piano |
561 // roll) -- any notes that ended earlier will have been reported | 572 // roll) -- any notes that ended earlier will have been reported |
562 // already, and if they haven't ended, we don't know their | 573 // already, and if they haven't ended, we don't know their |
563 // duration. | 574 // duration. |
564 | 575 |
565 int postFilterLatency = int(m_postFilter[0]->getSize() / 2); | 576 int postFilterLatency = int(m_postFilter[0]->getSize() / 2); |
566 | 577 |
567 int width = m_pianoRoll.size(); | 578 int width = m_pianoRoll.size() - 1; |
579 | |
580 const map<int, double> &active = m_pianoRoll[width]; | |
568 | 581 |
569 double columnDuration = 1.0 / m_colsPerSec; | 582 double columnDuration = 1.0 / m_colsPerSec; |
570 | 583 |
571 // only keep notes >= 100ms or thereabouts | 584 // only keep notes >= 100ms or thereabouts |
572 int durationThreshold = floor(0.1 / columnDuration); // columns | 585 int durationThreshold = floor(0.1 / columnDuration); // columns |
573 if (durationThreshold < 1) durationThreshold = 1; | 586 if (durationThreshold < 1) durationThreshold = 1; |
574 | 587 |
575 FeatureList noteFeatures; | 588 FeatureList noteFeatures; |
576 | 589 |
577 if (width < durationThreshold + 1) { | 590 if (width < durationThreshold + 1) { |
578 m_pianoRoll.push_back(active); | |
579 return noteFeatures; | 591 return noteFeatures; |
580 } | 592 } |
581 | 593 |
582 //!!! try: repeated note detection? (look for change in first derivative of the pitch matrix) | 594 //!!! try: repeated note detection? (look for change in first derivative of the pitch matrix) |
583 | 595 |
629 nf.values.push_back(velocity); | 641 nf.values.push_back(velocity); |
630 nf.label = noteName(note); | 642 nf.label = noteName(note); |
631 noteFeatures.push_back(nf); | 643 noteFeatures.push_back(nf); |
632 } | 644 } |
633 | 645 |
634 m_pianoRoll.push_back(active); | |
635 | |
636 // cerr << "returning " << noteFeatures.size() << " complete note(s) " << endl; | 646 // cerr << "returning " << noteFeatures.size() << " complete note(s) " << endl; |
637 | 647 |
638 return noteFeatures; | 648 return noteFeatures; |
639 } | 649 } |
640 | 650 |