Mercurial > hg > silvet
comparison src/Silvet.cpp @ 309:07ee4ebea57c
Add chromagram output
author | Chris Cannam |
---|---|
date | Mon, 19 Jan 2015 11:23:07 +0000 |
parents | 04a3c152e590 |
children | 99af9557dfc1 |
comparison
equal
deleted
inserted
replaced
305:04a3c152e590 | 309:07ee4ebea57c |
---|---|
86 } | 86 } |
87 | 87 |
88 int | 88 int |
89 Silvet::getPluginVersion() const | 89 Silvet::getPluginVersion() const |
90 { | 90 { |
91 return 2; | 91 return 3; |
92 } | 92 } |
93 | 93 |
94 string | 94 string |
95 Silvet::getCopyright() const | 95 Silvet::getCopyright() const |
96 { | 96 { |
288 d.sampleRate = m_colsPerSec; | 288 d.sampleRate = m_colsPerSec; |
289 d.hasDuration = false; | 289 d.hasDuration = false; |
290 m_pitchOutputNo = list.size(); | 290 m_pitchOutputNo = list.size(); |
291 list.push_back(d); | 291 list.push_back(d); |
292 | 292 |
293 d.identifier = "chroma"; | |
294 d.name = "Pitch chroma distribution"; | |
295 d.description = "Pitch chroma distribution formed by wrapping the un-thresholded pitch activation distribution into a single octave of semitone bins."; | |
296 d.unit = ""; | |
297 d.hasFixedBinCount = true; | |
298 d.binCount = 12; | |
299 d.binNames.clear(); | |
300 if (m_cq) { | |
301 for (int i = 0; i < 12; ++i) { | |
302 d.binNames.push_back(chromaName(i)); | |
303 } | |
304 } | |
305 d.hasKnownExtents = false; | |
306 d.isQuantized = false; | |
307 d.sampleType = OutputDescriptor::FixedSampleRate; | |
308 d.sampleRate = m_colsPerSec; | |
309 d.hasDuration = false; | |
310 m_chromaOutputNo = list.size(); | |
311 list.push_back(d); | |
312 | |
293 return list; | 313 return list; |
294 } | 314 } |
295 | 315 |
296 std::string | 316 std::string |
297 Silvet::noteName(int note, int shift, int shiftCount) const | 317 Silvet::chromaName(int pitch) const |
298 { | 318 { |
299 static const char *names[] = { | 319 static const char *names[] = { |
300 "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#" | 320 "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#" |
301 }; | 321 }; |
302 | 322 |
303 const char *n = names[note % 12]; | 323 return names[pitch]; |
324 } | |
325 | |
326 std::string | |
327 Silvet::noteName(int note, int shift, int shiftCount) const | |
328 { | |
329 string n = chromaName(note % 12); | |
304 | 330 |
305 int oct = (note + 9) / 12; | 331 int oct = (note + 9) / 12; |
306 | 332 |
307 char buf[30]; | 333 char buf[30]; |
308 | 334 |
312 pshift = | 338 pshift = |
313 float((shiftCount - shift) - int(shiftCount / 2) - 1) / shiftCount; | 339 float((shiftCount - shift) - int(shiftCount / 2) - 1) / shiftCount; |
314 } | 340 } |
315 | 341 |
316 if (pshift > 0.f) { | 342 if (pshift > 0.f) { |
317 sprintf(buf, "%s%d+%dc", n, oct, int(round(pshift * 100))); | 343 sprintf(buf, "%s%d+%dc", n.c_str(), oct, int(round(pshift * 100))); |
318 } else if (pshift < 0.f) { | 344 } else if (pshift < 0.f) { |
319 sprintf(buf, "%s%d-%dc", n, oct, int(round((-pshift) * 100))); | 345 sprintf(buf, "%s%d-%dc", n.c_str(), oct, int(round((-pshift) * 100))); |
320 } else { | 346 } else { |
321 sprintf(buf, "%s%d", n, oct); | 347 sprintf(buf, "%s%d", n.c_str(), oct); |
322 } | 348 } |
323 | 349 |
324 return buf; | 350 return buf; |
325 } | 351 } |
326 | 352 |
573 } | 599 } |
574 } | 600 } |
575 | 601 |
576 for (int i = 0; i < width; ++i) { | 602 for (int i = 0; i < width; ++i) { |
577 | 603 |
604 // This returns a filtered column, and pushes the | |
605 // up-to-max-polyphony activation column to m_pianoRoll | |
578 vector<double> filtered = postProcess | 606 vector<double> filtered = postProcess |
579 (localPitches[i], localBestShifts[i], wantShifts); | 607 (localPitches[i], localBestShifts[i], wantShifts); |
580 | 608 |
609 RealTime timestamp = getColumnTimestamp(m_pianoRoll.size() - 1); | |
610 float inputGain = getInputGainAt(timestamp); | |
611 | |
581 Feature f; | 612 Feature f; |
582 for (int j = 0; j < (int)filtered.size(); ++j) { | 613 for (int j = 0; j < (int)filtered.size(); ++j) { |
583 float v(filtered[j]); | 614 float v = filtered[j]; |
584 if (v < pack.levelThreshold) v = 0.f; | 615 if (v < pack.levelThreshold) v = 0.f; |
585 f.values.push_back(v); | 616 f.values.push_back(v / inputGain); |
586 } | 617 } |
587 fs[m_pitchOutputNo].push_back(f); | 618 fs[m_pitchOutputNo].push_back(f); |
619 | |
620 f.values.clear(); | |
621 f.values.resize(12); | |
622 for (int j = 0; j < (int)filtered.size(); ++j) { | |
623 f.values[j % 12] += filtered[j] / inputGain; | |
624 } | |
625 fs[m_chromaOutputNo].push_back(f); | |
588 | 626 |
589 FeatureList noteFeatures = noteTrack(shiftCount); | 627 FeatureList noteFeatures = noteTrack(shiftCount); |
590 | 628 |
591 for (FeatureList::const_iterator fi = noteFeatures.begin(); | 629 for (FeatureList::const_iterator fi = noteFeatures.begin(); |
592 fi != noteFeatures.end(); ++fi) { | 630 fi != noteFeatures.end(); ++fi) { |
849 shiftCount, | 887 shiftCount, |
850 partVelocity)); | 888 partVelocity)); |
851 } | 889 } |
852 } | 890 } |
853 | 891 |
892 RealTime | |
893 Silvet::getColumnTimestamp(int column) | |
894 { | |
895 double columnDuration = 1.0 / m_colsPerSec; | |
896 int postFilterLatency = int(m_postFilter[0]->getSize() / 2); | |
897 | |
898 return m_startTime + RealTime::fromSeconds | |
899 (columnDuration * (column - postFilterLatency) + 0.02); | |
900 } | |
901 | |
854 Silvet::Feature | 902 Silvet::Feature |
855 Silvet::makeNoteFeature(int start, | 903 Silvet::makeNoteFeature(int start, |
856 int end, | 904 int end, |
857 int note, | 905 int note, |
858 int shift, | 906 int shift, |
859 int shiftCount, | 907 int shiftCount, |
860 int velocity) | 908 int velocity) |
861 { | 909 { |
862 double columnDuration = 1.0 / m_colsPerSec; | |
863 int postFilterLatency = int(m_postFilter[0]->getSize() / 2); | |
864 | |
865 Feature f; | 910 Feature f; |
866 | 911 |
867 f.hasTimestamp = true; | 912 f.hasTimestamp = true; |
868 f.timestamp = m_startTime + RealTime::fromSeconds | 913 f.timestamp = getColumnTimestamp(start); |
869 (columnDuration * (start - postFilterLatency) + 0.02); | |
870 | 914 |
871 f.hasDuration = true; | 915 f.hasDuration = true; |
872 f.duration = RealTime::fromSeconds | 916 f.duration = getColumnTimestamp(end) - f.timestamp; |
873 (columnDuration * (end - start)); | |
874 | 917 |
875 f.values.clear(); | 918 f.values.clear(); |
876 | 919 |
877 f.values.push_back | 920 f.values.push_back |
878 (noteFrequency(note, shift, shiftCount)); | 921 (noteFrequency(note, shift, shiftCount)); |