comparison layer/NoteLayer.cpp @ 1424:2ee77c9974d7 single-point

Toward getting NoteLayer to work with single-point APIs
author Chris Cannam
date Wed, 13 Mar 2019 16:00:55 +0000
parents 62e908518c71
children f9e3126d223c
comparison
equal deleted inserted replaced
1423:62e908518c71 1424:2ee77c9974d7
388 } 388 }
389 389
390 return mapper; 390 return mapper;
391 } 391 }
392 392
393 NoteModel::PointList 393 EventVector
394 NoteLayer::getLocalPoints(LayerGeometryProvider *v, int x) const 394 NoteLayer::getLocalPoints(LayerGeometryProvider *v, int x) const
395 { 395 {
396 if (!m_model) return NoteModel::PointList(); 396 if (!m_model) return {};
397 397
398 sv_frame_t frame = v->getFrameForX(x); 398 sv_frame_t frame = v->getFrameForX(x);
399 399
400 NoteModel::PointList onPoints = 400 EventVector local = m_model->getEventsCovering(frame);
401 m_model->getPoints(frame); 401 if (!local.empty()) return local;
402 402
403 if (!onPoints.empty()) { 403 int fuzz = ViewManager::scalePixelSize(2);
404 return onPoints; 404 sv_frame_t start = v->getFrameForX(x - fuzz);
405 } 405 sv_frame_t end = v->getFrameForX(x + fuzz);
406 406
407 NoteModel::PointList prevPoints = 407 local = m_model->getEventsStartingWithin(frame, end - frame);
408 m_model->getPreviousPoints(frame); 408 if (!local.empty()) return local;
409 NoteModel::PointList nextPoints = 409
410 m_model->getNextPoints(frame); 410 local = m_model->getEventsSpanning(start, frame - start);
411 411 if (!local.empty()) return local;
412 NoteModel::PointList usePoints = prevPoints; 412
413 413 return {};
414 if (prevPoints.empty()) {
415 usePoints = nextPoints;
416 } else if (int(prevPoints.begin()->frame) < v->getStartFrame() &&
417 !(nextPoints.begin()->frame > v->getEndFrame())) {
418 usePoints = nextPoints;
419 } else if (int(nextPoints.begin()->frame) - frame <
420 frame - int(prevPoints.begin()->frame)) {
421 usePoints = nextPoints;
422 }
423
424 if (!usePoints.empty()) {
425 int fuzz = ViewManager::scalePixelSize(2);
426 int px = v->getXForFrame(usePoints.begin()->frame);
427 if ((px > x && px - x > fuzz) ||
428 (px < x && x - px > fuzz + 1)) {
429 usePoints.clear();
430 }
431 }
432
433 return usePoints;
434 } 414 }
435 415
436 bool 416 bool
437 NoteLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, NoteModel::Point &p) const 417 NoteLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, Event &point) const
438 { 418 {
439 if (!m_model) return false; 419 if (!m_model) return false;
440 420
441 sv_frame_t frame = v->getFrameForX(x); 421 sv_frame_t frame = v->getFrameForX(x);
442 422
443 NoteModel::PointList onPoints = m_model->getPoints(frame); 423 EventVector onPoints = m_model->getEventsCovering(frame);
444 if (onPoints.empty()) return false; 424 if (onPoints.empty()) return false;
445 425
446 // cerr << "frame " << frame << ": " << onPoints.size() << " candidate points" << endl;
447
448 int nearestDistance = -1; 426 int nearestDistance = -1;
449 427 for (const auto &p: onPoints) {
450 for (NoteModel::PointList::const_iterator i = onPoints.begin(); 428 int distance = getYForValue(v, p.getValue()) - y;
451 i != onPoints.end(); ++i) {
452
453 int distance = getYForValue(v, (*i).value) - y;
454 if (distance < 0) distance = -distance; 429 if (distance < 0) distance = -distance;
455 if (nearestDistance == -1 || distance < nearestDistance) { 430 if (nearestDistance == -1 || distance < nearestDistance) {
456 nearestDistance = distance; 431 nearestDistance = distance;
457 p = *i; 432 point = p;
458 } 433 }
459 } 434 }
460 435
461 return true; 436 return true;
462 } 437 }
466 { 441 {
467 int x = pos.x(); 442 int x = pos.x();
468 443
469 if (!m_model || !m_model->getSampleRate()) return ""; 444 if (!m_model || !m_model->getSampleRate()) return "";
470 445
471 NoteModel::PointList points = getLocalPoints(v, x); 446 EventVector points = getLocalPoints(v, x);
472 447
473 if (points.empty()) { 448 if (points.empty()) {
474 if (!m_model->isReady()) { 449 if (!m_model->isReady()) {
475 return tr("In progress"); 450 return tr("In progress");
476 } else { 451 } else {
477 return tr("No local points"); 452 return tr("No local points");
478 } 453 }
479 } 454 }
480 455
481 Note note(0); 456 Event note;
482 NoteModel::PointList::iterator i; 457 EventVector::iterator i;
483 458
484 for (i = points.begin(); i != points.end(); ++i) { 459 for (i = points.begin(); i != points.end(); ++i) {
485 460
486 int y = getYForValue(v, i->value); 461 int y = getYForValue(v, i->getValue());
487 int h = 3; 462 int h = 3;
488 463
489 if (m_model->getValueQuantization() != 0.0) { 464 if (m_model->getValueQuantization() != 0.0) {
490 h = y - getYForValue(v, i->value + m_model->getValueQuantization()); 465 h = y - getYForValue
466 (v, i->getValue() + m_model->getValueQuantization());
491 if (h < 3) h = 3; 467 if (h < 3) h = 3;
492 } 468 }
493 469
494 if (pos.y() >= y - h && pos.y() <= y) { 470 if (pos.y() >= y - h && pos.y() <= y) {
495 note = *i; 471 note = *i;
497 } 473 }
498 } 474 }
499 475
500 if (i == points.end()) return tr("No local points"); 476 if (i == points.end()) return tr("No local points");
501 477
502 RealTime rt = RealTime::frame2RealTime(note.frame, 478 RealTime rt = RealTime::frame2RealTime(note.getFrame(),
503 m_model->getSampleRate()); 479 m_model->getSampleRate());
504 RealTime rd = RealTime::frame2RealTime(note.duration, 480 RealTime rd = RealTime::frame2RealTime(note.getDuration(),
505 m_model->getSampleRate()); 481 m_model->getSampleRate());
506 482
507 QString pitchText; 483 QString pitchText;
508 484
485 float value = note.getValue();
486
509 if (shouldConvertMIDIToHz()) { 487 if (shouldConvertMIDIToHz()) {
510 488
511 int mnote = int(lrint(note.value)); 489 int mnote = int(lrint(value));
512 int cents = int(lrint((note.value - float(mnote)) * 100)); 490 int cents = int(lrint((value - float(mnote)) * 100));
513 double freq = Pitch::getFrequencyForPitch(mnote, cents); 491 double freq = Pitch::getFrequencyForPitch(mnote, cents);
514 pitchText = tr("%1 (%2, %3 Hz)") 492 pitchText = tr("%1 (%2, %3 Hz)")
515 .arg(Pitch::getPitchLabel(mnote, cents)) 493 .arg(Pitch::getPitchLabel(mnote, cents))
516 .arg(mnote) 494 .arg(mnote)
517 .arg(freq); 495 .arg(freq);
518 496
519 } else if (getScaleUnits() == "Hz") { 497 } else if (getScaleUnits() == "Hz") {
520 498
521 pitchText = tr("%1 Hz (%2, %3)") 499 pitchText = tr("%1 Hz (%2, %3)")
522 .arg(note.value) 500 .arg(value)
523 .arg(Pitch::getPitchLabelForFrequency(note.value)) 501 .arg(Pitch::getPitchLabelForFrequency(value))
524 .arg(Pitch::getPitchForFrequency(note.value)); 502 .arg(Pitch::getPitchForFrequency(value));
525 503
526 } else { 504 } else {
527 pitchText = tr("%1 %2") 505 pitchText = tr("%1 %2")
528 .arg(note.value).arg(getScaleUnits()); 506 .arg(value).arg(getScaleUnits());
529 } 507 }
530 508
531 QString text; 509 QString text;
532 510
533 if (note.label == "") { 511 if (note.getLabel() == "") {
534 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nNo label")) 512 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nNo label"))
535 .arg(rt.toText(true).c_str()) 513 .arg(rt.toText(true).c_str())
536 .arg(pitchText) 514 .arg(pitchText)
537 .arg(rd.toText(true).c_str()); 515 .arg(rd.toText(true).c_str());
538 } else { 516 } else {
539 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nLabel:\t%4")) 517 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nLabel:\t%4"))
540 .arg(rt.toText(true).c_str()) 518 .arg(rt.toText(true).c_str())
541 .arg(pitchText) 519 .arg(pitchText)
542 .arg(rd.toText(true).c_str()) 520 .arg(rd.toText(true).c_str())
543 .arg(note.label); 521 .arg(note.getLabel());
544 } 522 }
545 523
546 pos = QPoint(v->getXForFrame(note.frame), 524 pos = QPoint(v->getXForFrame(note.getFrame()), getYForValue(v, value));
547 getYForValue(v, note.value));
548 return text; 525 return text;
549 } 526 }
550 527
551 bool 528 bool
552 NoteLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, 529 NoteLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
556 if (!m_model) { 533 if (!m_model) {
557 return Layer::snapToFeatureFrame(v, frame, resolution, snap); 534 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
558 } 535 }
559 536
560 resolution = m_model->getResolution(); 537 resolution = m_model->getResolution();
561 NoteModel::PointList points; 538 EventVector points;
562 539
563 if (snap == SnapNeighbouring) { 540 if (snap == SnapNeighbouring) {
564 541
565 points = getLocalPoints(v, v->getXForFrame(frame)); 542 points = getLocalPoints(v, v->getXForFrame(frame));
566 if (points.empty()) return false; 543 if (points.empty()) return false;
567 frame = points.begin()->frame; 544 frame = points.begin()->getFrame();
568 return true; 545 return true;
569 } 546 }
570 547
571 points = m_model->getPoints(frame, frame); 548 points = m_model->getEventsCovering(frame);
572 sv_frame_t snapped = frame; 549 sv_frame_t snapped = frame;
573 bool found = false; 550 bool found = false;
574 551
575 for (NoteModel::PointList::const_iterator i = points.begin(); 552 for (EventVector::const_iterator i = points.begin();
576 i != points.end(); ++i) { 553 i != points.end(); ++i) {
577 554
578 if (snap == SnapRight) { 555 if (snap == SnapRight) {
579 556
580 if (i->frame > frame) { 557 if (i->getFrame() > frame) {
581 snapped = i->frame; 558 snapped = i->getFrame();
582 found = true; 559 found = true;
583 break; 560 break;
584 } 561 }
585 562
586 } else if (snap == SnapLeft) { 563 } else if (snap == SnapLeft) {
587 564
588 if (i->frame <= frame) { 565 if (i->getFrame() <= frame) {
589 snapped = i->frame; 566 snapped = i->getFrame();
590 found = true; // don't break, as the next may be better 567 found = true; // don't break, as the next may be better
591 } else { 568 } else {
592 break; 569 break;
593 } 570 }
594 571
595 } else { // nearest 572 } else { // nearest
596 573
597 NoteModel::PointList::const_iterator j = i; 574 EventVector::const_iterator j = i;
598 ++j; 575 ++j;
599 576
600 if (j == points.end()) { 577 if (j == points.end()) {
601 578
602 snapped = i->frame; 579 snapped = i->getFrame();
603 found = true; 580 found = true;
604 break; 581 break;
605 582
606 } else if (j->frame >= frame) { 583 } else if (j->getFrame() >= frame) {
607 584
608 if (j->frame - frame < frame - i->frame) { 585 if (j->getFrame() - frame < frame - i->getFrame()) {
609 snapped = j->frame; 586 snapped = j->getFrame();
610 } else { 587 } else {
611 snapped = i->frame; 588 snapped = i->getFrame();
612 } 589 }
613 found = true; 590 found = true;
614 break; 591 break;
615 } 592 }
616 } 593 }