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