Mercurial > hg > svgui
diff layer/NoteLayer.cpp @ 1459:42c87368287c
Merge from branch single-point
author | Chris Cannam |
---|---|
date | Fri, 17 May 2019 10:02:52 +0100 |
parents | 5b9692768beb |
children | 696e569ff21b |
line wrap: on
line diff
--- a/layer/NoteLayer.cpp Wed Apr 24 11:29:53 2019 +0100 +++ b/layer/NoteLayer.cpp Fri May 17 10:02:52 2019 +0100 @@ -390,71 +390,46 @@ return mapper; } -NoteModel::PointList +EventVector NoteLayer::getLocalPoints(LayerGeometryProvider *v, int x) const { - if (!m_model) return NoteModel::PointList(); - + if (!m_model) return {}; + sv_frame_t frame = v->getFrameForX(x); - NoteModel::PointList onPoints = - m_model->getPoints(frame); + EventVector local = m_model->getEventsCovering(frame); + if (!local.empty()) return local; - if (!onPoints.empty()) { - return onPoints; - } + int fuzz = ViewManager::scalePixelSize(2); + sv_frame_t start = v->getFrameForX(x - fuzz); + sv_frame_t end = v->getFrameForX(x + fuzz); - NoteModel::PointList prevPoints = - m_model->getPreviousPoints(frame); - NoteModel::PointList nextPoints = - m_model->getNextPoints(frame); + local = m_model->getEventsStartingWithin(frame, end - frame); + if (!local.empty()) return local; - NoteModel::PointList usePoints = prevPoints; + local = m_model->getEventsSpanning(start, frame - start); + if (!local.empty()) return local; - if (prevPoints.empty()) { - usePoints = nextPoints; - } else if (int(prevPoints.begin()->frame) < v->getStartFrame() && - !(nextPoints.begin()->frame > v->getEndFrame())) { - usePoints = nextPoints; - } else if (int(nextPoints.begin()->frame) - frame < - frame - int(prevPoints.begin()->frame)) { - usePoints = nextPoints; - } - - if (!usePoints.empty()) { - int fuzz = ViewManager::scalePixelSize(2); - int px = v->getXForFrame(usePoints.begin()->frame); - if ((px > x && px - x > fuzz) || - (px < x && x - px > fuzz + 1)) { - usePoints.clear(); - } - } - - return usePoints; + return {}; } bool -NoteLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, NoteModel::Point &p) const +NoteLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, Event &point) const { if (!m_model) return false; sv_frame_t frame = v->getFrameForX(x); - NoteModel::PointList onPoints = m_model->getPoints(frame); + EventVector onPoints = m_model->getEventsCovering(frame); if (onPoints.empty()) return false; -// cerr << "frame " << frame << ": " << onPoints.size() << " candidate points" << endl; - int nearestDistance = -1; - - for (NoteModel::PointList::const_iterator i = onPoints.begin(); - i != onPoints.end(); ++i) { - - int distance = getYForValue(v, (*i).value) - y; + for (const auto &p: onPoints) { + int distance = getYForValue(v, p.getValue()) - y; if (distance < 0) distance = -distance; if (nearestDistance == -1 || distance < nearestDistance) { nearestDistance = distance; - p = *i; + point = p; } } @@ -468,7 +443,7 @@ if (!m_model || !m_model->getSampleRate()) return ""; - NoteModel::PointList points = getLocalPoints(v, x); + EventVector points = getLocalPoints(v, x); if (points.empty()) { if (!m_model->isReady()) { @@ -478,16 +453,17 @@ } } - Note note(0); - NoteModel::PointList::iterator i; + Event note; + EventVector::iterator i; for (i = points.begin(); i != points.end(); ++i) { - int y = getYForValue(v, i->value); + int y = getYForValue(v, i->getValue()); int h = 3; if (m_model->getValueQuantization() != 0.0) { - h = y - getYForValue(v, i->value + m_model->getValueQuantization()); + h = y - getYForValue + (v, i->getValue() + m_model->getValueQuantization()); if (h < 3) h = 3; } @@ -499,17 +475,19 @@ if (i == points.end()) return tr("No local points"); - RealTime rt = RealTime::frame2RealTime(note.frame, + RealTime rt = RealTime::frame2RealTime(note.getFrame(), m_model->getSampleRate()); - RealTime rd = RealTime::frame2RealTime(note.duration, + RealTime rd = RealTime::frame2RealTime(note.getDuration(), m_model->getSampleRate()); QString pitchText; + float value = note.getValue(); + if (shouldConvertMIDIToHz()) { - int mnote = int(lrint(note.value)); - int cents = int(lrint((note.value - float(mnote)) * 100)); + int mnote = int(lrint(value)); + int cents = int(lrint((value - float(mnote)) * 100)); double freq = Pitch::getFrequencyForPitch(mnote, cents); pitchText = tr("%1 (%2, %3 Hz)") .arg(Pitch::getPitchLabel(mnote, cents)) @@ -519,18 +497,18 @@ } else if (getScaleUnits() == "Hz") { pitchText = tr("%1 Hz (%2, %3)") - .arg(note.value) - .arg(Pitch::getPitchLabelForFrequency(note.value)) - .arg(Pitch::getPitchForFrequency(note.value)); + .arg(value) + .arg(Pitch::getPitchLabelForFrequency(value)) + .arg(Pitch::getPitchForFrequency(value)); } else { pitchText = tr("%1 %2") - .arg(note.value).arg(getScaleUnits()); + .arg(value).arg(getScaleUnits()); } QString text; - if (note.label == "") { + if (note.getLabel() == "") { text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nNo label")) .arg(rt.toText(true).c_str()) .arg(pitchText) @@ -540,11 +518,10 @@ .arg(rt.toText(true).c_str()) .arg(pitchText) .arg(rd.toText(true).c_str()) - .arg(note.label); + .arg(note.getLabel()); } - pos = QPoint(v->getXForFrame(note.frame), - getYForValue(v, note.value)); + pos = QPoint(v->getXForFrame(note.getFrame()), getYForValue(v, value)); return text; } @@ -557,67 +534,33 @@ return Layer::snapToFeatureFrame(v, frame, resolution, snap); } + // SnapLeft / SnapRight: return frame of nearest feature in that + // direction no matter how far away + // + // SnapNeighbouring: return frame of feature that would be used in + // an editing operation, i.e. closest feature in either direction + // but only if it is "close enough" + resolution = m_model->getResolution(); - NoteModel::PointList points; if (snap == SnapNeighbouring) { - - points = getLocalPoints(v, v->getXForFrame(frame)); + EventVector points = getLocalPoints(v, v->getXForFrame(frame)); if (points.empty()) return false; - frame = points.begin()->frame; + frame = points.begin()->getFrame(); return true; } - points = m_model->getPoints(frame, frame); - sv_frame_t snapped = frame; - bool found = false; - - for (NoteModel::PointList::const_iterator i = points.begin(); - i != points.end(); ++i) { - - if (snap == SnapRight) { - - if (i->frame > frame) { - snapped = i->frame; - found = true; - break; - } - - } else if (snap == SnapLeft) { - - if (i->frame <= frame) { - snapped = i->frame; - found = true; // don't break, as the next may be better - } else { - break; - } - - } else { // nearest - - NoteModel::PointList::const_iterator j = i; - ++j; - - if (j == points.end()) { - - snapped = i->frame; - found = true; - break; - - } else if (j->frame >= frame) { - - if (j->frame - frame < frame - i->frame) { - snapped = j->frame; - } else { - snapped = i->frame; - } - found = true; - break; - } - } + Event e; + if (m_model->getNearestEventMatching + (frame, + [](Event) { return true; }, + snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward, + e)) { + frame = e.getFrame(); + return true; } - frame = snapped; - return found; + return false; } void @@ -756,7 +699,7 @@ sv_frame_t frame0 = v->getFrameForX(x0); sv_frame_t frame1 = v->getFrameForX(x1); - NoteModel::PointList points(m_model->getPoints(frame0, frame1)); + EventVector points(m_model->getEventsSpanning(frame0, frame1 - frame0)); if (points.empty()) return; paint.setPen(getBaseQColor()); @@ -772,7 +715,7 @@ if (max == min) max = min + 1.0; QPoint localPos; - NoteModel::Point illuminatePoint(0); + Event illuminatePoint; bool shouldIlluminate = false; if (v->shouldIlluminateLocalFeatures(this, localPos)) { @@ -786,18 +729,18 @@ paint.save(); paint.setRenderHint(QPainter::Antialiasing, false); - for (NoteModel::PointList::const_iterator i = points.begin(); + for (EventVector::const_iterator i = points.begin(); i != points.end(); ++i) { - const NoteModel::Point &p(*i); + const Event &p(*i); - int x = v->getXForFrame(p.frame); - int y = getYForValue(v, p.value); - int w = v->getXForFrame(p.frame + p.duration) - x; + int x = v->getXForFrame(p.getFrame()); + int y = getYForValue(v, p.getValue()); + int w = v->getXForFrame(p.getFrame() + p.getDuration()) - x; int h = 3; if (m_model->getValueQuantization() != 0.0) { - h = y - getYForValue(v, p.value + m_model->getValueQuantization()); + h = y - getYForValue(v, p.getValue() + m_model->getValueQuantization()); if (h < 3) h = 3; } @@ -805,15 +748,12 @@ paint.setPen(getBaseQColor()); paint.setBrush(brushColour); - if (shouldIlluminate && - // "illuminatePoint == p" - !NoteModel::Point::Comparator()(illuminatePoint, p) && - !NoteModel::Point::Comparator()(p, illuminatePoint)) { + if (shouldIlluminate && illuminatePoint == p) { paint.setPen(v->getForeground()); paint.setBrush(v->getForeground()); - QString vlabel = QString("%1%2").arg(p.value).arg(getScaleUnits()); + QString vlabel = QString("%1%2").arg(p.getValue()).arg(getScaleUnits()); PaintAssistant::drawVisibleText(v, paint, x - paint.fontMetrics().width(vlabel) - 2, y + paint.fontMetrics().height()/2 @@ -821,7 +761,7 @@ vlabel, PaintAssistant::OutlinedText); QString hlabel = RealTime::frame2RealTime - (p.frame, m_model->getSampleRate()).toText(true).c_str(); + (p.getFrame(), m_model->getSampleRate()).toText(true).c_str(); PaintAssistant::drawVisibleText(v, paint, x, y - h/2 - paint.fontMetrics().descent() - 2, @@ -855,7 +795,7 @@ void NoteLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const { - if (!m_model || m_model->getPoints().empty()) return; + if (!m_model || m_model->isEmpty()) return; QString unit; double min, max; @@ -903,13 +843,12 @@ double value = getValueForY(v, e->y()); - m_editingPoint = NoteModel::Point(frame, float(value), 0, 0.8f, tr("New Point")); + m_editingPoint = Event(frame, float(value), 0, 0.8f, tr("New Point")); m_originalPoint = m_editingPoint; if (m_editingCommand) finish(m_editingCommand); - m_editingCommand = new NoteModel::EditCommand(m_model, - tr("Draw Point")); - m_editingCommand->addPoint(m_editingPoint); + m_editingCommand = new ChangeEventsCommand(m_model, tr("Draw Point")); + m_editingCommand->add(m_editingPoint); m_editing = true; } @@ -927,7 +866,7 @@ double newValue = getValueForY(v, e->y()); - sv_frame_t newFrame = m_editingPoint.frame; + sv_frame_t newFrame = m_editingPoint.getFrame(); sv_frame_t newDuration = frame - newFrame; if (newDuration < 0) { newFrame = frame; @@ -936,11 +875,12 @@ newDuration = 1; } - m_editingCommand->deletePoint(m_editingPoint); - m_editingPoint.frame = newFrame; - m_editingPoint.value = float(newValue); - m_editingPoint.duration = newDuration; - m_editingCommand->addPoint(m_editingPoint); + m_editingCommand->remove(m_editingPoint); + m_editingPoint = m_editingPoint + .withFrame(newFrame) + .withValue(float(newValue)) + .withDuration(newDuration); + m_editingCommand->add(m_editingPoint); } void @@ -980,13 +920,14 @@ m_editing = false; - NoteModel::Point p(0); + Event p(0); if (!getPointToDrag(v, e->x(), e->y(), p)) return; - if (p.frame != m_editingPoint.frame || p.value != m_editingPoint.value) return; + if (p.getFrame() != m_editingPoint.getFrame() || + p.getValue() != m_editingPoint.getValue()) return; - m_editingCommand = new NoteModel::EditCommand(m_model, tr("Erase Point")); + m_editingCommand = new ChangeEventsCommand(m_model, tr("Erase Point")); - m_editingCommand->deletePoint(m_editingPoint); + m_editingCommand->remove(m_editingPoint); finish(m_editingCommand); m_editingCommand = nullptr; @@ -1003,8 +944,8 @@ if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return; m_originalPoint = m_editingPoint; - m_dragPointX = v->getXForFrame(m_editingPoint.frame); - m_dragPointY = getYForValue(v, m_editingPoint.value); + m_dragPointX = v->getXForFrame(m_editingPoint.getFrame()); + m_dragPointY = getYForValue(v, m_editingPoint.getValue()); if (m_editingCommand) { finish(m_editingCommand); @@ -1035,14 +976,15 @@ double value = getValueForY(v, newy); if (!m_editingCommand) { - m_editingCommand = new NoteModel::EditCommand(m_model, + m_editingCommand = new ChangeEventsCommand(m_model, tr("Drag Point")); } - m_editingCommand->deletePoint(m_editingPoint); - m_editingPoint.frame = frame; - m_editingPoint.value = float(value); - m_editingCommand->addPoint(m_editingPoint); + m_editingCommand->remove(m_editingPoint); + m_editingPoint = m_editingPoint + .withFrame(frame) + .withValue(float(value)); + m_editingCommand->add(m_editingPoint); } void @@ -1055,8 +997,8 @@ QString newName = m_editingCommand->getName(); - if (m_editingPoint.frame != m_originalPoint.frame) { - if (m_editingPoint.value != m_originalPoint.value) { + if (m_editingPoint.getFrame() != m_originalPoint.getFrame()) { + if (m_editingPoint.getValue() != m_originalPoint.getValue()) { newName = tr("Edit Point"); } else { newName = tr("Relocate Point"); @@ -1078,10 +1020,10 @@ { if (!m_model) return false; - NoteModel::Point note(0); + Event note(0); if (!getPointToDrag(v, e->x(), e->y(), note)) return false; -// NoteModel::Point note = *points.begin(); +// Event note = *points.begin(); ItemEditDialog *dialog = new ItemEditDialog (m_model->getSampleRate(), @@ -1091,26 +1033,26 @@ ItemEditDialog::ShowText, getScaleUnits()); - dialog->setFrameTime(note.frame); - dialog->setValue(note.value); - dialog->setFrameDuration(note.duration); - dialog->setText(note.label); + dialog->setFrameTime(note.getFrame()); + dialog->setValue(note.getValue()); + dialog->setFrameDuration(note.getDuration()); + dialog->setText(note.getLabel()); m_editingPoint = note; m_editIsOpen = true; if (dialog->exec() == QDialog::Accepted) { - NoteModel::Point newNote = note; - newNote.frame = dialog->getFrameTime(); - newNote.value = dialog->getValue(); - newNote.duration = dialog->getFrameDuration(); - newNote.label = dialog->getText(); + Event newNote = note + .withFrame(dialog->getFrameTime()) + .withValue(dialog->getValue()) + .withDuration(dialog->getFrameDuration()) + .withLabel(dialog->getText()); - NoteModel::EditCommand *command = new NoteModel::EditCommand + ChangeEventsCommand *command = new ChangeEventsCommand (m_model, tr("Edit Point")); - command->deletePoint(note); - command->addPoint(newNote); + command->remove(note); + command->add(newNote); finish(command); } @@ -1126,21 +1068,17 @@ { if (!m_model) return; - NoteModel::EditCommand *command = - new NoteModel::EditCommand(m_model, tr("Drag Selection")); + ChangeEventsCommand *command = + new ChangeEventsCommand(m_model, tr("Drag Selection")); - NoteModel::PointList points = - m_model->getPoints(s.getStartFrame(), s.getEndFrame()); + EventVector points = + m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); - for (NoteModel::PointList::iterator i = points.begin(); - i != points.end(); ++i) { - - if (s.contains(i->frame)) { - NoteModel::Point newPoint(*i); - newPoint.frame = i->frame + newStartFrame - s.getStartFrame(); - command->deletePoint(*i); - command->addPoint(newPoint); - } + for (Event p: points) { + command->remove(p); + Event moved = p.withFrame(p.getFrame() + + newStartFrame - s.getStartFrame()); + command->add(moved); } finish(command); @@ -1149,37 +1087,28 @@ void NoteLayer::resizeSelection(Selection s, Selection newSize) { - if (!m_model) return; + if (!m_model || !s.getDuration()) return; - NoteModel::EditCommand *command = - new NoteModel::EditCommand(m_model, tr("Resize Selection")); + ChangeEventsCommand *command = + new ChangeEventsCommand(m_model, tr("Resize Selection")); - NoteModel::PointList points = - m_model->getPoints(s.getStartFrame(), s.getEndFrame()); + EventVector points = + m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); - double ratio = - double(newSize.getEndFrame() - newSize.getStartFrame()) / - double(s.getEndFrame() - s.getStartFrame()); + double ratio = double(newSize.getDuration()) / double(s.getDuration()); + double oldStart = double(s.getStartFrame()); + double newStart = double(newSize.getStartFrame()); + + for (Event p: points) { - for (NoteModel::PointList::iterator i = points.begin(); - i != points.end(); ++i) { + double newFrame = (double(p.getFrame()) - oldStart) * ratio + newStart; + double newDuration = double(p.getDuration()) * ratio; - if (s.contains(i->frame)) { - - double targetStart = double(i->frame); - targetStart = double(newSize.getStartFrame()) + - targetStart - double(s.getStartFrame()) * ratio; - - double targetEnd = double(i->frame + i->duration); - targetEnd = double(newSize.getStartFrame()) + - targetEnd - double(s.getStartFrame()) * ratio; - - NoteModel::Point newPoint(*i); - newPoint.frame = lrint(targetStart); - newPoint.duration = lrint(targetEnd - targetStart); - command->deletePoint(*i); - command->addPoint(newPoint); - } + Event newPoint = p + .withFrame(lrint(newFrame)) + .withDuration(lrint(newDuration)); + command->remove(p); + command->add(newPoint); } finish(command); @@ -1190,18 +1119,14 @@ { if (!m_model) return; - NoteModel::EditCommand *command = - new NoteModel::EditCommand(m_model, tr("Delete Selected Points")); + ChangeEventsCommand *command = + new ChangeEventsCommand(m_model, tr("Delete Selected Points")); - NoteModel::PointList points = - m_model->getPoints(s.getStartFrame(), s.getEndFrame()); + EventVector points = + m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); - for (NoteModel::PointList::iterator i = points.begin(); - i != points.end(); ++i) { - - if (s.contains(i->frame)) { - command->deletePoint(*i); - } + for (Event p: points) { + command->remove(p); } finish(command); @@ -1212,25 +1137,21 @@ { if (!m_model) return; - NoteModel::PointList points = - m_model->getPoints(s.getStartFrame(), s.getEndFrame()); + EventVector points = + m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); - for (NoteModel::PointList::iterator i = points.begin(); - i != points.end(); ++i) { - if (s.contains(i->frame)) { - Clipboard::Point point(i->frame, i->value, i->duration, i->level, i->label); - point.setReferenceFrame(alignToReference(v, i->frame)); - to.addPoint(point); - } + for (Event p: points) { + to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame()))); } } bool -NoteLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) +NoteLayer::paste(LayerGeometryProvider *v, const Clipboard &from, + sv_frame_t /* frameOffset */, bool /* interactive */) { if (!m_model) return false; - const Clipboard::PointList &points = from.getPoints(); + const EventVector &points = from.getPoints(); bool realign = false; @@ -1251,13 +1172,12 @@ } } - NoteModel::EditCommand *command = - new NoteModel::EditCommand(m_model, tr("Paste")); + ChangeEventsCommand *command = + new ChangeEventsCommand(m_model, tr("Paste")); - for (Clipboard::PointList::const_iterator i = points.begin(); + for (EventVector::const_iterator i = points.begin(); i != points.end(); ++i) { - - if (!i->haveFrame()) continue; + sv_frame_t frame = 0; if (!realign) { @@ -1266,7 +1186,7 @@ } else { - if (i->haveReferenceFrame()) { + if (i->hasReferenceFrame()) { frame = i->getReferenceFrame(); frame = alignFromReference(v, frame); } else { @@ -1274,32 +1194,29 @@ } } - NoteModel::Point newPoint(frame); - - if (i->haveLabel()) newPoint.label = i->getLabel(); - if (i->haveValue()) newPoint.value = i->getValue(); - else newPoint.value = (m_model->getValueMinimum() + - m_model->getValueMaximum()) / 2; - if (i->haveLevel()) newPoint.level = i->getLevel(); - if (i->haveDuration()) newPoint.duration = i->getDuration(); - else { + Event p = *i; + Event newPoint = p; + if (!p.hasValue()) { + newPoint = newPoint.withValue((m_model->getValueMinimum() + + m_model->getValueMaximum()) / 2); + } + if (!p.hasDuration()) { sv_frame_t nextFrame = frame; - Clipboard::PointList::const_iterator j = i; + EventVector::const_iterator j = i; for (; j != points.end(); ++j) { - if (!j->haveFrame()) continue; if (j != i) break; } if (j != points.end()) { nextFrame = j->getFrame(); } if (nextFrame == frame) { - newPoint.duration = m_model->getResolution(); + newPoint = newPoint.withDuration(m_model->getResolution()); } else { - newPoint.duration = nextFrame - frame; + newPoint = newPoint.withDuration(nextFrame - frame); } } - command->addPoint(newPoint); + command->add(newPoint); } finish(command); @@ -1309,7 +1226,8 @@ void NoteLayer::addNoteOn(sv_frame_t frame, int pitch, int velocity) { - m_pendingNoteOns.insert(Note(frame, float(pitch), 0, float(velocity) / 127.f, "")); + m_pendingNoteOns.insert(Event(frame, float(pitch), 0, + float(velocity) / 127.f, QString())); } void @@ -1317,13 +1235,16 @@ { for (NoteSet::iterator i = m_pendingNoteOns.begin(); i != m_pendingNoteOns.end(); ++i) { - if (lrintf((*i).value) == pitch) { - Note note(*i); + + Event p = *i; + + if (lrintf(p.getValue()) == pitch) { m_pendingNoteOns.erase(i); - note.duration = frame - note.frame; + Event note = p.withDuration(frame - p.getFrame()); if (m_model) { - NoteModel::AddPointCommand *c = new NoteModel::AddPointCommand - (m_model, note, tr("Record Note")); + ChangeEventsCommand *c = new ChangeEventsCommand + (m_model, tr("Record Note")); + c->add(note); // execute and bundle: CommandHistory::getInstance()->addCommand(c, true, true); }