Mercurial > hg > silvet
comparison src/Silvet.cpp @ 180:2931089cda46 f0
Have a first go at reporting f0
author | Chris Cannam |
---|---|
date | Thu, 22 May 2014 16:59:12 +0100 |
parents | 825193ef09d2 |
children |
comparison
equal
deleted
inserted
replaced
179:825193ef09d2 | 180:2931089cda46 |
---|---|
17 #include "EM.h" | 17 #include "EM.h" |
18 | 18 |
19 #include <cq/CQSpectrogram.h> | 19 #include <cq/CQSpectrogram.h> |
20 | 20 |
21 #include "MedianFilter.h" | 21 #include "MedianFilter.h" |
22 #include "PeakInterpolator.h" | |
23 | |
22 #include "constant-q-cpp/src/dsp/Resampler.h" | 24 #include "constant-q-cpp/src/dsp/Resampler.h" |
23 | 25 |
24 #include <vector> | 26 #include <vector> |
25 | 27 |
26 #include <cstdio> | 28 #include <cstdio> |
237 d.isQuantized = false; | 239 d.isQuantized = false; |
238 d.sampleType = OutputDescriptor::VariableSampleRate; | 240 d.sampleType = OutputDescriptor::VariableSampleRate; |
239 d.sampleRate = m_inputSampleRate / (m_cq ? m_cq->getColumnHop() : 62); | 241 d.sampleRate = m_inputSampleRate / (m_cq ? m_cq->getColumnHop() : 62); |
240 d.hasDuration = true; | 242 d.hasDuration = true; |
241 m_notesOutputNo = list.size(); | 243 m_notesOutputNo = list.size(); |
244 list.push_back(d); | |
245 | |
246 d.identifier = "f0"; | |
247 d.name = "Predominant fundamental frequency"; | |
248 d.description = "Interpolated frequency of fundamental of most salient pitch at each time frame"; | |
249 d.unit = "Hz"; | |
250 d.hasFixedBinCount = true; | |
251 d.binCount = 1; | |
252 d.binNames.push_back("Frequency"); | |
253 d.hasKnownExtents = false; | |
254 d.isQuantized = false; | |
255 d.sampleType = OutputDescriptor::FixedSampleRate; | |
256 d.sampleRate = m_colsPerSec; | |
257 d.hasDuration = false; | |
258 m_f0OutputNo = list.size(); | |
242 list.push_back(d); | 259 list.push_back(d); |
243 | 260 |
244 d.identifier = "timefreq"; | 261 d.identifier = "timefreq"; |
245 d.name = "Time-frequency distribution"; | 262 d.name = "Time-frequency distribution"; |
246 d.description = "Filtered constant-Q time-frequency distribution used as input to the expectation-maximisation algorithm"; | 263 d.description = "Filtered constant-Q time-frequency distribution used as input to the expectation-maximisation algorithm"; |
519 } | 536 } |
520 continue; | 537 continue; |
521 } | 538 } |
522 | 539 |
523 postProcess(localPitches[i], localBestShifts[i], wantShifts); | 540 postProcess(localPitches[i], localBestShifts[i], wantShifts); |
541 | |
542 FeatureList f0Features = convertF0Features(filtered[i], shiftCount); | |
543 | |
544 for (FeatureList::const_iterator fi = f0Features.begin(); | |
545 fi != f0Features.end(); ++fi) { | |
546 fs[m_f0OutputNo].push_back(*fi); | |
547 } | |
524 | 548 |
525 FeatureList noteFeatures = noteTrack(shiftCount); | 549 FeatureList noteFeatures = noteTrack(shiftCount); |
526 | 550 |
527 for (FeatureList::const_iterator fi = noteFeatures.begin(); | 551 for (FeatureList::const_iterator fi = noteFeatures.begin(); |
528 fi != noteFeatures.end(); ++fi) { | 552 fi != noteFeatures.end(); ++fi) { |
652 ValueIndexMap::const_iterator si = strengths.end(); | 676 ValueIndexMap::const_iterator si = strengths.end(); |
653 | 677 |
654 map<int, double> active; | 678 map<int, double> active; |
655 map<int, int> activeShifts; | 679 map<int, int> activeShifts; |
656 | 680 |
681 m_predominantNote = -1; | |
682 m_predominantShift = -1; | |
683 | |
657 while (int(active.size()) < polyphony && si != strengths.begin()) { | 684 while (int(active.size()) < polyphony && si != strengths.begin()) { |
658 | 685 |
659 --si; | 686 --si; |
660 | 687 |
661 double strength = si->first; | 688 double strength = si->first; |
662 int j = si->second; | 689 int j = si->second; |
663 | 690 |
664 active[j] = strength; | 691 active[j] = strength; |
665 | 692 |
693 if (m_predominantNote < 0) { | |
694 m_predominantNote = j; | |
695 } | |
696 | |
666 if (wantShifts) { | 697 if (wantShifts) { |
698 | |
667 activeShifts[j] = bestShifts[j]; | 699 activeShifts[j] = bestShifts[j]; |
700 | |
701 if (m_predominantShift < 0) { | |
702 m_predominantShift = bestShifts[j]; | |
703 } | |
668 } | 704 } |
669 } | 705 } |
670 | 706 |
671 m_pianoRoll.push_back(active); | 707 m_pianoRoll.push_back(active); |
672 | 708 |
673 if (wantShifts) { | 709 if (wantShifts) { |
674 m_pianoRollShifts.push_back(activeShifts); | 710 m_pianoRollShifts.push_back(activeShifts); |
675 } | 711 } |
712 } | |
713 | |
714 Vamp::Plugin::FeatureList | |
715 Silvet::convertF0Features(const vector<double> &column, int shiftCount) | |
716 { | |
717 FeatureList fl; | |
718 | |
719 if (m_predominantNote < 0) { | |
720 Feature f; | |
721 f.hasTimestamp = false; | |
722 f.hasDuration = false; | |
723 f.values.push_back(0.f); | |
724 fl.push_back(f); | |
725 return fl; | |
726 } | |
727 | |
728 int f0bin = m_predominantNote * shiftCount; | |
729 | |
730 if (m_predominantShift >= 0) { | |
731 f0bin += (shiftCount - m_predominantShift) - int(shiftCount / 2) - 1; | |
732 } | |
733 | |
734 PeakInterpolator pi; | |
735 float interpolated = (float)pi.findPeakLocation | |
736 (column.data(), column.size(), f0bin); | |
737 | |
738 float f0 = m_cq->getBinFrequency | |
739 (m_instruments[0].templateHeight - interpolated - 1.f); | |
740 | |
741 cerr << "note = " << m_predominantNote << " shift = " << m_predominantShift << " f0bin = " << f0bin << " interpolated = " << interpolated << " f0 = " << f0 << endl; | |
742 | |
743 Feature f; | |
744 f.hasTimestamp = false; | |
745 f.hasDuration = false; | |
746 f.values.push_back(f0); | |
747 fl.push_back(f); | |
748 return fl; | |
676 } | 749 } |
677 | 750 |
678 Vamp::Plugin::FeatureList | 751 Vamp::Plugin::FeatureList |
679 Silvet::noteTrack(int shiftCount) | 752 Silvet::noteTrack(int shiftCount) |
680 { | 753 { |