Mercurial > hg > svgui
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 } |