comparison src/Silvet.cpp @ 176:8af9b6cd7451

Add some ensemble instrument packs
author Chris Cannam
date Wed, 21 May 2014 15:03:12 +0100
parents abfd19f5cc1a
children a53c713b2a4a
comparison
equal deleted inserted replaced
175:abfd19f5cc1a 176:8af9b6cd7451
31 using std::endl; 31 using std::endl;
32 using Vamp::RealTime; 32 using Vamp::RealTime;
33 33
34 static int processingSampleRate = 44100; 34 static int processingSampleRate = 44100;
35 static int processingBPO = 60; 35 static int processingBPO = 60;
36
37 //!!! todo: replace these two with values from instrument pack
38 static int processingHeight = 545;
39 static int processingNotes = 88;
40 36
41 Silvet::Silvet(float inputSampleRate) : 37 Silvet::Silvet(float inputSampleRate) :
42 Plugin(inputSampleRate), 38 Plugin(inputSampleRate),
43 m_instruments(InstrumentPack::listInstrumentPacks()), 39 m_instruments(InstrumentPack::listInstrumentPacks()),
44 m_resampler(0), 40 m_resampler(0),
147 desc.quantizeStep = 1; 143 desc.quantizeStep = 1;
148 desc.valueNames.push_back("Draft (faster)"); 144 desc.valueNames.push_back("Draft (faster)");
149 desc.valueNames.push_back("Intensive (higher quality)"); 145 desc.valueNames.push_back("Intensive (higher quality)");
150 list.push_back(desc); 146 list.push_back(desc);
151 147
152 desc.identifier = "soloinstrument"; 148 desc.identifier = "instrument";
153 desc.name = "Solo instrument"; 149 desc.name = "Instrument";
154 desc.unit = ""; 150 desc.unit = "";
155 desc.description = "The instrument known to be present in the recording, if there is only one"; 151 desc.description = "The instrument known to be present in the recording, if there is only one";
156 desc.minValue = 0; 152 desc.minValue = 0;
157 desc.maxValue = m_instruments.size()-1; 153 desc.maxValue = m_instruments.size()-1;
158 desc.defaultValue = 0; 154 desc.defaultValue = 0;
184 { 180 {
185 if (identifier == "mode") { 181 if (identifier == "mode") {
186 return m_hqMode ? 1.f : 0.f; 182 return m_hqMode ? 1.f : 0.f;
187 } else if (identifier == "finetune") { 183 } else if (identifier == "finetune") {
188 return m_fineTuning ? 1.f : 0.f; 184 return m_fineTuning ? 1.f : 0.f;
189 } else if (identifier == "soloinstrument") { 185 } else if (identifier == "instrument") {
190 return m_instrument; 186 return m_instrument;
191 } 187 }
192 return 0; 188 return 0;
193 } 189 }
194 190
197 { 193 {
198 if (identifier == "mode") { 194 if (identifier == "mode") {
199 m_hqMode = (value > 0.5); 195 m_hqMode = (value > 0.5);
200 } else if (identifier == "finetune") { 196 } else if (identifier == "finetune") {
201 m_fineTuning = (value > 0.5); 197 m_fineTuning = (value > 0.5);
202 } else if (identifier == "soloinstrument") { 198 } else if (identifier == "instrument") {
203 m_instrument = lrintf(value); 199 m_instrument = lrintf(value);
204 } 200 }
205 } 201 }
206 202
207 Silvet::ProgramList 203 Silvet::ProgramList
362 358
363 for (int i = 0; i < (int)m_postFilter.size(); ++i) { 359 for (int i = 0; i < (int)m_postFilter.size(); ++i) {
364 delete m_postFilter[i]; 360 delete m_postFilter[i];
365 } 361 }
366 m_postFilter.clear(); 362 m_postFilter.clear();
367 for (int i = 0; i < processingNotes; ++i) { 363 for (int i = 0; i < m_instruments[0].templateNoteCount; ++i) {
368 m_postFilter.push_back(new MedianFilter<double>(3)); 364 m_postFilter.push_back(new MedianFilter<double>(3));
369 } 365 }
370 m_pianoRoll.clear(); 366 m_pianoRoll.clear();
371 m_columnCount = 0; 367 m_columnCount = 0;
372 m_startTime = RealTime::zeroTime; 368 m_startTime = RealTime::zeroTime;
425 int width = filtered.size(); 421 int width = filtered.size();
426 422
427 int iterations = m_hqMode ? 20 : 10; 423 int iterations = m_hqMode ? 20 : 10;
428 424
429 //!!! pitches or notes? [terminology] 425 //!!! pitches or notes? [terminology]
430 Grid localPitches(width, vector<double>(processingNotes, 0.0)); 426 Grid localPitches(width, vector<double>(pack.templateNoteCount, 0.0));
431 427
432 bool wantShifts = m_hqMode && m_fineTuning; 428 bool wantShifts = m_hqMode && m_fineTuning;
433 int shiftCount = 1; 429 int shiftCount = 1;
434 if (wantShifts) { 430 if (wantShifts) {
435 shiftCount = pack.templateMaxShift * 2 + 1; 431 shiftCount = pack.templateMaxShift * 2 + 1;
436 } 432 }
437 433
438 vector<vector<int> > localBestShifts; 434 vector<vector<int> > localBestShifts;
439 if (wantShifts) { 435 if (wantShifts) {
440 localBestShifts = 436 localBestShifts =
441 vector<vector<int> >(width, vector<int>(processingNotes, 0)); 437 vector<vector<int> >(width, vector<int>(pack.templateNoteCount, 0));
442 } 438 }
443 439
444 vector<bool> present(width, false); 440 vector<bool> present(width, false);
445 441
446 #pragma omp parallel for 442 #pragma omp parallel for
447 for (int i = 0; i < width; ++i) { 443 for (int i = 0; i < width; ++i) {
448 444
449 double sum = 0.0; 445 double sum = 0.0;
450 for (int j = 0; j < processingHeight; ++j) { 446 for (int j = 0; j < pack.templateHeight; ++j) {
451 sum += filtered.at(i).at(j); 447 sum += filtered.at(i).at(j);
452 } 448 }
453 if (sum < 1e-5) continue; 449 if (sum < 1e-5) continue;
454 450
455 present[i] = true; 451 present[i] = true;
461 } 457 }
462 458
463 const float *pitchDist = em.getPitchDistribution(); 459 const float *pitchDist = em.getPitchDistribution();
464 const float *const *shiftDist = em.getShifts(); 460 const float *const *shiftDist = em.getShifts();
465 461
466 for (int j = 0; j < processingNotes; ++j) { 462 for (int j = 0; j < pack.templateNoteCount; ++j) {
467 463
468 localPitches[i][j] = pitchDist[j] * sum; 464 localPitches[i][j] = pitchDist[j] * sum;
469 465
470 int bestShift = 0; 466 int bestShift = 0;
471 int bestShiftValue = 0.0; 467 int bestShiftValue = 0.0;
483 479
484 for (int i = 0; i < width; ++i) { 480 for (int i = 0; i < width; ++i) {
485 481
486 if (!present[i]) { 482 if (!present[i]) {
487 // silent column 483 // silent column
488 for (int j = 0; j < processingNotes; ++j) { 484 for (int j = 0; j < pack.templateNoteCount; ++j) {
489 m_postFilter[j]->push(0.0); 485 m_postFilter[j]->push(0.0);
490 } 486 }
491 m_pianoRoll.push_back(map<int, double>()); 487 m_pianoRoll.push_back(map<int, double>());
492 if (wantShifts) { 488 if (wantShifts) {
493 m_pianoRollShifts.push_back(map<int, int>()); 489 m_pianoRollShifts.push_back(map<int, int>());
525 // isn't quite accurate. But the small constant offset is 521 // isn't quite accurate. But the small constant offset is
526 // practically irrelevant compared to the jitter from the frame 522 // practically irrelevant compared to the jitter from the frame
527 // size we reduce to in a moment 523 // size we reduce to in a moment
528 int latentColumns = m_cq->getLatency() / m_cq->getColumnHop(); 524 int latentColumns = m_cq->getLatency() / m_cq->getColumnHop();
529 525
526 const InstrumentPack &pack = m_instruments[m_instrument];
527
530 for (int i = 0; i < width; ++i) { 528 for (int i = 0; i < width; ++i) {
531 529
532 if (m_columnCount < latentColumns) { 530 if (m_columnCount < latentColumns) {
533 ++m_columnCount; 531 ++m_columnCount;
534 continue; 532 continue;
539 537
540 bool select = (sampleNo / spacing != prevSampleNo / spacing); 538 bool select = (sampleNo / spacing != prevSampleNo / spacing);
541 539
542 if (select) { 540 if (select) {
543 vector<double> inCol = in[i]; 541 vector<double> inCol = in[i];
544 vector<double> outCol(processingHeight); 542 vector<double> outCol(pack.templateHeight);
545 543
546 // we reverse the column as we go (the CQ output is 544 // we reverse the column as we go (the CQ output is
547 // "upside-down", with high frequencies at the start of 545 // "upside-down", with high frequencies at the start of
548 // each column, and we want it the other way around) and 546 // each column, and we want it the other way around) and
549 // then ignore the first 55 (lowest-frequency) bins, 547 // then ignore the first 55 (lowest-frequency) bins,
550 // giving us 545 bins instead of 600 548 // giving us 545 bins instead of 600
551 549
552 for (int j = 0; j < processingHeight; ++j) { 550 for (int j = 0; j < pack.templateHeight; ++j) {
553 int ix = inCol.size() - j - 55; 551 int ix = inCol.size() - j - 55;
554 outCol[j] = inCol[ix]; 552 outCol[j] = inCol[ix];
555 } 553 }
556 554
557 vector<double> noiseLevel1 = 555 vector<double> noiseLevel1 =
558 MedianFilter<double>::filter(40, outCol); 556 MedianFilter<double>::filter(40, outCol);
559 for (int j = 0; j < processingHeight; ++j) { 557 for (int j = 0; j < pack.templateHeight; ++j) {
560 noiseLevel1[j] = std::min(outCol[j], noiseLevel1[j]); 558 noiseLevel1[j] = std::min(outCol[j], noiseLevel1[j]);
561 } 559 }
562 560
563 vector<double> noiseLevel2 = 561 vector<double> noiseLevel2 =
564 MedianFilter<double>::filter(40, noiseLevel1); 562 MedianFilter<double>::filter(40, noiseLevel1);
565 for (int j = 0; j < processingHeight; ++j) { 563 for (int j = 0; j < pack.templateHeight; ++j) {
566 outCol[j] = std::max(outCol[j] - noiseLevel2[j], 0.0); 564 outCol[j] = std::max(outCol[j] - noiseLevel2[j], 0.0);
567 } 565 }
568 566
569 out.push_back(outCol); 567 out.push_back(outCol);
570 } 568 }
578 void 576 void
579 Silvet::postProcess(const vector<double> &pitches, 577 Silvet::postProcess(const vector<double> &pitches,
580 const vector<int> &bestShifts, 578 const vector<int> &bestShifts,
581 bool wantShifts) 579 bool wantShifts)
582 { 580 {
581 const InstrumentPack &pack = m_instruments[m_instrument];
582
583 vector<double> filtered; 583 vector<double> filtered;
584 584
585 for (int j = 0; j < processingNotes; ++j) { 585 for (int j = 0; j < pack.templateNoteCount; ++j) {
586 m_postFilter[j]->push(pitches[j]); 586 m_postFilter[j]->push(pitches[j]);
587 filtered.push_back(m_postFilter[j]->get()); 587 filtered.push_back(m_postFilter[j]->get());
588 } 588 }
589 589
590 // Threshold for level and reduce number of candidate pitches 590 // Threshold for level and reduce number of candidate pitches
597 597
598 typedef std::multimap<double, int> ValueIndexMap; 598 typedef std::multimap<double, int> ValueIndexMap;
599 599
600 ValueIndexMap strengths; 600 ValueIndexMap strengths;
601 601
602 for (int j = 0; j < processingNotes; ++j) { 602 for (int j = 0; j < pack.templateNoteCount; ++j) {
603 double strength = filtered[j]; 603 double strength = filtered[j];
604 if (strength < threshold) continue; 604 if (strength < threshold) continue;
605 strengths.insert(ValueIndexMap::value_type(strength, j)); 605 strengths.insert(ValueIndexMap::value_type(strength, j));
606 } 606 }
607 607