annotate layer/FlexiNoteLayer.cpp @ 855:57efeb75880d

Simplify some logic where loop was used with an unconditional "break" that meant it could only happen once (from coverity scan)
author Chris Cannam
date Wed, 03 Sep 2014 12:05:45 +0100
parents 5d4e3e36945f
children 7a80fa6a6dfc e0f08e108064
rev   line source
Chris@58 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@30 2
Chris@30 3 /*
Chris@59 4 Sonic Visualiser
Chris@59 5 An audio file viewer and annotation editor.
Chris@59 6 Centre for Digital Music, Queen Mary, University of London.
Chris@59 7 This file copyright 2006 Chris Cannam.
Chris@30 8
Chris@59 9 This program is free software; you can redistribute it and/or
Chris@59 10 modify it under the terms of the GNU General Public License as
Chris@59 11 published by the Free Software Foundation; either version 2 of the
Chris@59 12 License, or (at your option) any later version. See the file
Chris@59 13 COPYING included with this distribution for more information.
Chris@30 14 */
Chris@30 15
matthiasm@620 16 #include "FlexiNoteLayer.h"
Chris@30 17
Chris@128 18 #include "data/model/Model.h"
gyorgyf@655 19 #include "data/model/SparseTimeValueModel.h"
Chris@30 20 #include "base/RealTime.h"
Chris@30 21 #include "base/Profiler.h"
Chris@30 22 #include "base/Pitch.h"
Chris@197 23 #include "base/LogRange.h"
Chris@439 24 #include "base/RangeMapper.h"
Chris@376 25 #include "ColourDatabase.h"
Chris@128 26 #include "view/View.h"
Chris@701 27
Chris@692 28 #include "PianoScale.h"
Chris@701 29 #include "LinearNumericalScale.h"
Chris@701 30 #include "LogNumericalScale.h"
Chris@30 31
matthiasm@620 32 #include "data/model/FlexiNoteModel.h"
Chris@30 33
Chris@70 34 #include "widgets/ItemEditDialog.h"
Chris@701 35 #include "widgets/TextAbbrev.h"
Chris@70 36
Chris@30 37 #include <QPainter>
Chris@30 38 #include <QPainterPath>
Chris@30 39 #include <QMouseEvent>
Chris@316 40 #include <QTextStream>
Chris@360 41 #include <QMessageBox>
Chris@30 42
Chris@30 43 #include <iostream>
Chris@30 44 #include <cmath>
Chris@551 45 #include <utility>
gyorgyf@655 46 #include <limits> // GF: included to compile std::numerical_limits on linux
gyorgyf@655 47 #include <vector>
gyorgyf@655 48
Chris@30 49
matthiasm@620 50 FlexiNoteLayer::FlexiNoteLayer() :
gyorgyf@646 51 SingleColourLayer(),
gyorgyf@625 52
Chris@714 53 // m_model(0),
Chris@714 54 // m_editing(false),
Chris@714 55 // m_originalPoint(0, 0.0, 0, 1.f, tr("New Point")),
Chris@714 56 // m_editingPoint(0, 0.0, 0, 1.f, tr("New Point")),
Chris@714 57 // m_editingCommand(0),
Chris@714 58 // m_verticalScale(AutoAlignScale),
Chris@714 59 // m_scaleMinimum(0),
Chris@714 60 // m_scaleMaximum(0)
gyorgyf@625 61
gyorgyf@627 62 m_model(0),
gyorgyf@628 63 m_editing(false),
Chris@805 64 m_intelligentActions(true),
Chris@844 65 m_dragPointX(0),
Chris@844 66 m_dragPointY(0),
Chris@844 67 m_dragStartX(0),
Chris@844 68 m_dragStartY(0),
gyorgyf@627 69 m_originalPoint(0, 0.0, 0, 1.f, tr("New Point")),
gyorgyf@627 70 m_editingPoint(0, 0.0, 0, 1.f, tr("New Point")),
Chris@844 71 m_greatestLeftNeighbourFrame(0),
Chris@844 72 m_smallestRightNeighbourFrame(0),
gyorgyf@627 73 m_editingCommand(0),
matthiasm@634 74 m_verticalScale(AutoAlignScale),
Chris@688 75 m_editMode(DragNote),
gyorgyf@628 76 m_scaleMinimum(34),
Chris@805 77 m_scaleMaximum(77)
Chris@30 78 {
Chris@30 79 }
Chris@30 80
Chris@30 81 void
gyorgyf@626 82 FlexiNoteLayer::setModel(FlexiNoteModel *model)
Chris@30 83 {
Chris@30 84 if (m_model == model) return;
Chris@30 85 m_model = model;
Chris@30 86
Chris@320 87 connectSignals(m_model);
Chris@30 88
gyorgyf@628 89 // m_scaleMinimum = 0;
gyorgyf@628 90 // m_scaleMaximum = 0;
Chris@439 91
Chris@30 92 emit modelReplaced();
Chris@30 93 }
Chris@30 94
Chris@30 95 Layer::PropertyList
matthiasm@620 96 FlexiNoteLayer::getProperties() const
Chris@30 97 {
Chris@287 98 PropertyList list = SingleColourLayer::getProperties();
Chris@87 99 list.push_back("Vertical Scale");
Chris@100 100 list.push_back("Scale Units");
Chris@30 101 return list;
Chris@30 102 }
Chris@30 103
Chris@87 104 QString
matthiasm@620 105 FlexiNoteLayer::getPropertyLabel(const PropertyName &name) const
Chris@87 106 {
Chris@87 107 if (name == "Vertical Scale") return tr("Vertical Scale");
Chris@116 108 if (name == "Scale Units") return tr("Scale Units");
Chris@287 109 return SingleColourLayer::getPropertyLabel(name);
Chris@87 110 }
Chris@87 111
Chris@30 112 Layer::PropertyType
matthiasm@620 113 FlexiNoteLayer::getPropertyType(const PropertyName &name) const
Chris@30 114 {
Chris@100 115 if (name == "Scale Units") return UnitsProperty;
Chris@287 116 if (name == "Vertical Scale") return ValueProperty;
Chris@287 117 return SingleColourLayer::getPropertyType(name);
Chris@30 118 }
Chris@30 119
Chris@198 120 QString
matthiasm@620 121 FlexiNoteLayer::getPropertyGroupName(const PropertyName &name) const
Chris@198 122 {
Chris@198 123 if (name == "Vertical Scale" || name == "Scale Units") {
Chris@198 124 return tr("Scale");
Chris@198 125 }
Chris@287 126 return SingleColourLayer::getPropertyGroupName(name);
Chris@198 127 }
Chris@198 128
Chris@701 129 QString
Chris@703 130 FlexiNoteLayer::getScaleUnits() const
Chris@701 131 {
Chris@701 132 if (m_model) return m_model->getScaleUnits();
Chris@701 133 else return "";
Chris@701 134 }
Chris@701 135
Chris@30 136 int
matthiasm@620 137 FlexiNoteLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@714 138 int *min, int *max, int *deflt) const
Chris@30 139 {
Chris@216 140 int val = 0;
Chris@30 141
Chris@287 142 if (name == "Vertical Scale") {
gyorgyf@646 143
Chris@714 144 if (min) *min = 0;
Chris@714 145 if (max) *max = 3;
Chris@216 146 if (deflt) *deflt = int(AutoAlignScale);
gyorgyf@646 147
Chris@714 148 val = int(m_verticalScale);
Chris@30 149
Chris@100 150 } else if (name == "Scale Units") {
Chris@100 151
Chris@216 152 if (deflt) *deflt = 0;
Chris@100 153 if (m_model) {
Chris@216 154 val = UnitDatabase::getInstance()->getUnitId
Chris@701 155 (getScaleUnits());
Chris@100 156 }
Chris@100 157
Chris@30 158 } else {
Chris@216 159
Chris@714 160 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
Chris@30 161 }
Chris@30 162
Chris@216 163 return val;
Chris@30 164 }
Chris@30 165
Chris@30 166 QString
matthiasm@620 167 FlexiNoteLayer::getPropertyValueLabel(const PropertyName &name,
Chris@714 168 int value) const
Chris@30 169 {
Chris@287 170 if (name == "Vertical Scale") {
Chris@714 171 switch (value) {
Chris@714 172 default:
Chris@714 173 case 0: return tr("Auto-Align");
Chris@714 174 case 1: return tr("Linear");
Chris@714 175 case 2: return tr("Log");
Chris@714 176 case 3: return tr("MIDI Notes");
Chris@714 177 }
Chris@30 178 }
Chris@287 179 return SingleColourLayer::getPropertyValueLabel(name, value);
Chris@30 180 }
Chris@30 181
Chris@30 182 void
matthiasm@620 183 FlexiNoteLayer::setProperty(const PropertyName &name, int value)
Chris@30 184 {
Chris@287 185 if (name == "Vertical Scale") {
Chris@714 186 setVerticalScale(VerticalScale(value));
Chris@100 187 } else if (name == "Scale Units") {
Chris@100 188 if (m_model) {
Chris@100 189 m_model->setScaleUnits
Chris@100 190 (UnitDatabase::getInstance()->getUnitById(value));
Chris@100 191 emit modelChanged();
Chris@100 192 }
Chris@287 193 } else {
Chris@287 194 return SingleColourLayer::setProperty(name, value);
Chris@30 195 }
Chris@30 196 }
Chris@30 197
Chris@30 198 void
matthiasm@620 199 FlexiNoteLayer::setVerticalScale(VerticalScale scale)
Chris@30 200 {
Chris@30 201 if (m_verticalScale == scale) return;
Chris@30 202 m_verticalScale = scale;
Chris@30 203 emit layerParametersChanged();
Chris@30 204 }
Chris@30 205
Chris@30 206 bool
matthiasm@620 207 FlexiNoteLayer::isLayerScrollable(const View *v) const
Chris@30 208 {
Chris@30 209 QPoint discard;
Chris@44 210 return !v->shouldIlluminateLocalFeatures(this, discard);
Chris@30 211 }
Chris@30 212
Chris@79 213 bool
matthiasm@620 214 FlexiNoteLayer::shouldConvertMIDIToHz() const
Chris@101 215 {
Chris@701 216 QString unit = getScaleUnits();
Chris@101 217 return (unit != "Hz");
Chris@101 218 // if (unit == "" ||
Chris@101 219 // unit.startsWith("MIDI") ||
Chris@101 220 // unit.startsWith("midi")) return true;
Chris@101 221 // return false;
Chris@101 222 }
Chris@101 223
Chris@101 224 bool
matthiasm@620 225 FlexiNoteLayer::getValueExtents(float &min, float &max,
Chris@714 226 bool &logarithmic, QString &unit) const
Chris@79 227 {
Chris@79 228 if (!m_model) return false;
Chris@79 229 min = m_model->getValueMinimum();
Chris@79 230 max = m_model->getValueMaximum();
Chris@101 231
Chris@105 232 if (shouldConvertMIDIToHz()) {
Chris@105 233 unit = "Hz";
Chris@105 234 min = Pitch::getFrequencyForPitch(lrintf(min));
Chris@105 235 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
Chris@701 236 } else unit = getScaleUnits();
Chris@101 237
Chris@101 238 if (m_verticalScale == MIDIRangeScale ||
Chris@101 239 m_verticalScale == LogScale) logarithmic = true;
Chris@101 240
Chris@101 241 return true;
Chris@101 242 }
Chris@101 243
Chris@101 244 bool
matthiasm@620 245 FlexiNoteLayer::getDisplayExtents(float &min, float &max) const
Chris@101 246 {
matthiasm@623 247 if (!m_model || shouldAutoAlign()) {
Chris@695 248 // std::cerr << "No model or shouldAutoAlign()" << std::endl;
gyorgyf@646 249 return false;
gyorgyf@646 250 }
Chris@101 251
Chris@101 252 if (m_verticalScale == MIDIRangeScale) {
Chris@101 253 min = Pitch::getFrequencyForPitch(0);
matthiasm@634 254 max = Pitch::getFrequencyForPitch(127);
Chris@101 255 return true;
Chris@101 256 }
Chris@101 257
Chris@439 258 if (m_scaleMinimum == m_scaleMaximum) {
Chris@455 259 min = m_model->getValueMinimum();
Chris@455 260 max = m_model->getValueMaximum();
Chris@455 261 } else {
Chris@455 262 min = m_scaleMinimum;
Chris@455 263 max = m_scaleMaximum;
Chris@439 264 }
Chris@439 265
Chris@101 266 if (shouldConvertMIDIToHz()) {
Chris@101 267 min = Pitch::getFrequencyForPitch(lrintf(min));
Chris@101 268 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
Chris@101 269 }
Chris@101 270
Chris@667 271 #ifdef DEBUG_NOTE_LAYER
Chris@682 272 cerr << "NoteLayer::getDisplayExtents: min = " << min << ", max = " << max << " (m_scaleMinimum = " << m_scaleMinimum << ", m_scaleMaximum = " << m_scaleMaximum << ")" << endl;
Chris@667 273 #endif
Chris@667 274
Chris@79 275 return true;
Chris@79 276 }
Chris@79 277
Chris@439 278 bool
matthiasm@620 279 FlexiNoteLayer::setDisplayExtents(float min, float max)
Chris@439 280 {
Chris@439 281 if (!m_model) return false;
Chris@439 282
Chris@439 283 if (min == max) {
Chris@439 284 if (min == 0.f) {
Chris@439 285 max = 1.f;
Chris@439 286 } else {
Chris@439 287 max = min * 1.0001;
Chris@439 288 }
Chris@439 289 }
Chris@439 290
Chris@439 291 m_scaleMinimum = min;
Chris@439 292 m_scaleMaximum = max;
Chris@439 293
Chris@667 294 #ifdef DEBUG_NOTE_LAYER
Chris@684 295 cerr << "FlexiNoteLayer::setDisplayExtents: min = " << min << ", max = " << max << endl;
Chris@667 296 #endif
Chris@439 297
Chris@439 298 emit layerParametersChanged();
Chris@439 299 return true;
Chris@439 300 }
Chris@439 301
Chris@439 302 int
matthiasm@620 303 FlexiNoteLayer::getVerticalZoomSteps(int &defaultStep) const
Chris@439 304 {
Chris@439 305 if (shouldAutoAlign()) return 0;
Chris@439 306 if (!m_model) return 0;
Chris@439 307
Chris@439 308 defaultStep = 0;
Chris@439 309 return 100;
Chris@439 310 }
Chris@439 311
Chris@439 312 int
matthiasm@620 313 FlexiNoteLayer::getCurrentVerticalZoomStep() const
Chris@439 314 {
Chris@439 315 if (shouldAutoAlign()) return 0;
Chris@439 316 if (!m_model) return 0;
Chris@439 317
Chris@439 318 RangeMapper *mapper = getNewVerticalZoomRangeMapper();
Chris@439 319 if (!mapper) return 0;
Chris@439 320
Chris@439 321 float dmin, dmax;
Chris@439 322 getDisplayExtents(dmin, dmax);
Chris@439 323
Chris@439 324 int nr = mapper->getPositionForValue(dmax - dmin);
Chris@439 325
Chris@439 326 delete mapper;
Chris@439 327
Chris@439 328 return 100 - nr;
Chris@439 329 }
Chris@439 330
Chris@439 331 //!!! lots of duplication with TimeValueLayer
Chris@439 332
Chris@439 333 void
matthiasm@620 334 FlexiNoteLayer::setVerticalZoomStep(int step)
Chris@439 335 {
Chris@439 336 if (shouldAutoAlign()) return;
Chris@439 337 if (!m_model) return;
Chris@439 338
Chris@439 339 RangeMapper *mapper = getNewVerticalZoomRangeMapper();
Chris@439 340 if (!mapper) return;
Chris@439 341
Chris@439 342 float min, max;
Chris@439 343 bool logarithmic;
Chris@439 344 QString unit;
Chris@439 345 getValueExtents(min, max, logarithmic, unit);
Chris@439 346
Chris@439 347 float dmin, dmax;
Chris@439 348 getDisplayExtents(dmin, dmax);
Chris@439 349
Chris@439 350 float newdist = mapper->getValueForPosition(100 - step);
Chris@439 351
Chris@439 352 float newmin, newmax;
Chris@439 353
Chris@439 354 if (logarithmic) {
Chris@439 355
Chris@439 356 // see SpectrogramLayer::setVerticalZoomStep
Chris@439 357
Chris@439 358 newmax = (newdist + sqrtf(newdist*newdist + 4*dmin*dmax)) / 2;
Chris@439 359 newmin = newmax - newdist;
Chris@439 360
Chris@682 361 // cerr << "newmin = " << newmin << ", newmax = " << newmax << endl;
Chris@439 362
Chris@439 363 } else {
Chris@439 364 float dmid = (dmax + dmin) / 2;
Chris@439 365 newmin = dmid - newdist / 2;
Chris@439 366 newmax = dmid + newdist / 2;
Chris@439 367 }
Chris@439 368
Chris@439 369 if (newmin < min) {
Chris@439 370 newmax += (min - newmin);
Chris@439 371 newmin = min;
Chris@439 372 }
Chris@439 373 if (newmax > max) {
Chris@439 374 newmax = max;
Chris@439 375 }
Chris@439 376
Chris@667 377 #ifdef DEBUG_NOTE_LAYER
Chris@684 378 cerr << "FlexiNoteLayer::setVerticalZoomStep: " << step << ": " << newmin << " -> " << newmax << " (range " << newdist << ")" << endl;
Chris@667 379 #endif
Chris@439 380
Chris@439 381 setDisplayExtents(newmin, newmax);
Chris@439 382 }
Chris@439 383
Chris@439 384 RangeMapper *
matthiasm@620 385 FlexiNoteLayer::getNewVerticalZoomRangeMapper() const
Chris@439 386 {
Chris@439 387 if (!m_model) return 0;
Chris@439 388
Chris@439 389 RangeMapper *mapper;
Chris@439 390
Chris@439 391 float min, max;
Chris@439 392 bool logarithmic;
Chris@439 393 QString unit;
Chris@439 394 getValueExtents(min, max, logarithmic, unit);
Chris@439 395
Chris@439 396 if (min == max) return 0;
Chris@439 397
Chris@439 398 if (logarithmic) {
Chris@439 399 mapper = new LogRangeMapper(0, 100, min, max, unit);
Chris@439 400 } else {
Chris@439 401 mapper = new LinearRangeMapper(0, 100, min, max, unit);
Chris@439 402 }
Chris@439 403
Chris@439 404 return mapper;
Chris@439 405 }
Chris@439 406
matthiasm@620 407 FlexiNoteModel::PointList
matthiasm@620 408 FlexiNoteLayer::getLocalPoints(View *v, int x) const
Chris@30 409 {
matthiasm@620 410 if (!m_model) return FlexiNoteModel::PointList();
Chris@30 411
Chris@806 412 int frame = v->getFrameForX(x);
Chris@30 413
matthiasm@620 414 FlexiNoteModel::PointList onPoints =
Chris@714 415 m_model->getPoints(frame);
Chris@30 416
Chris@30 417 if (!onPoints.empty()) {
Chris@714 418 return onPoints;
Chris@30 419 }
Chris@30 420
matthiasm@620 421 FlexiNoteModel::PointList prevPoints =
Chris@714 422 m_model->getPreviousPoints(frame);
matthiasm@620 423 FlexiNoteModel::PointList nextPoints =
Chris@714 424 m_model->getNextPoints(frame);
Chris@30 425
matthiasm@620 426 FlexiNoteModel::PointList usePoints = prevPoints;
Chris@30 427
Chris@30 428 if (prevPoints.empty()) {
Chris@714 429 usePoints = nextPoints;
Chris@805 430 } else if (prevPoints.begin()->frame < v->getStartFrame() &&
Chris@714 431 !(nextPoints.begin()->frame > v->getEndFrame())) {
Chris@714 432 usePoints = nextPoints;
Chris@805 433 } else if (nextPoints.begin()->frame - frame <
Chris@805 434 frame - prevPoints.begin()->frame) {
Chris@714 435 usePoints = nextPoints;
Chris@30 436 }
Chris@30 437
Chris@30 438 if (!usePoints.empty()) {
Chris@714 439 int fuzz = 2;
Chris@714 440 int px = v->getXForFrame(usePoints.begin()->frame);
Chris@714 441 if ((px > x && px - x > fuzz) ||
Chris@714 442 (px < x && x - px > fuzz + 1)) {
Chris@714 443 usePoints.clear();
Chris@714 444 }
Chris@30 445 }
Chris@30 446
Chris@30 447 return usePoints;
Chris@30 448 }
Chris@30 449
Chris@550 450 bool
matthiasm@622 451 FlexiNoteLayer::getPointToDrag(View *v, int x, int y, FlexiNoteModel::Point &p) const
Chris@550 452 {
Chris@550 453 if (!m_model) return false;
Chris@550 454
Chris@806 455 int frame = v->getFrameForX(x);
Chris@550 456
matthiasm@620 457 FlexiNoteModel::PointList onPoints = m_model->getPoints(frame);
Chris@550 458 if (onPoints.empty()) return false;
Chris@550 459
Chris@682 460 // cerr << "frame " << frame << ": " << onPoints.size() << " candidate points" << endl;
Chris@550 461
Chris@550 462 int nearestDistance = -1;
Chris@550 463
matthiasm@620 464 for (FlexiNoteModel::PointList::const_iterator i = onPoints.begin();
Chris@550 465 i != onPoints.end(); ++i) {
Chris@550 466
Chris@550 467 int distance = getYForValue(v, (*i).value) - y;
Chris@550 468 if (distance < 0) distance = -distance;
Chris@550 469 if (nearestDistance == -1 || distance < nearestDistance) {
Chris@550 470 nearestDistance = distance;
Chris@550 471 p = *i;
Chris@550 472 }
Chris@550 473 }
Chris@550 474
Chris@550 475 return true;
Chris@550 476 }
Chris@550 477
gyorgyf@646 478 bool
gyorgyf@646 479 FlexiNoteLayer::getNoteToEdit(View *v, int x, int y, FlexiNoteModel::Point &p) const
gyorgyf@646 480 {
gyorgyf@647 481 // GF: find the note that is closest to the cursor
gyorgyf@646 482 if (!m_model) return false;
gyorgyf@646 483
Chris@806 484 int frame = v->getFrameForX(x);
gyorgyf@646 485
gyorgyf@646 486 FlexiNoteModel::PointList onPoints = m_model->getPoints(frame);
gyorgyf@646 487 if (onPoints.empty()) return false;
gyorgyf@646 488
gyorgyf@646 489 // std::cerr << "frame " << frame << ": " << onPoints.size() << " candidate points" << std::endl;
gyorgyf@646 490
gyorgyf@646 491 int nearestDistance = -1;
gyorgyf@646 492
gyorgyf@646 493 for (FlexiNoteModel::PointList::const_iterator i = onPoints.begin();
gyorgyf@646 494 i != onPoints.end(); ++i) {
gyorgyf@646 495
gyorgyf@646 496 int distance = getYForValue(v, (*i).value) - y;
gyorgyf@646 497 if (distance < 0) distance = -distance;
gyorgyf@646 498 if (nearestDistance == -1 || distance < nearestDistance) {
gyorgyf@646 499 nearestDistance = distance;
gyorgyf@646 500 p = *i;
gyorgyf@646 501 }
gyorgyf@646 502 }
gyorgyf@646 503
gyorgyf@646 504 return true;
gyorgyf@646 505 }
gyorgyf@646 506
Chris@30 507 QString
matthiasm@620 508 FlexiNoteLayer::getFeatureDescription(View *v, QPoint &pos) const
Chris@30 509 {
Chris@30 510 int x = pos.x();
Chris@30 511
Chris@30 512 if (!m_model || !m_model->getSampleRate()) return "";
Chris@30 513
matthiasm@620 514 FlexiNoteModel::PointList points = getLocalPoints(v, x);
Chris@30 515
Chris@30 516 if (points.empty()) {
Chris@714 517 if (!m_model->isReady()) {
Chris@714 518 return tr("In progress");
Chris@714 519 } else {
Chris@714 520 return tr("No local points");
Chris@714 521 }
Chris@30 522 }
Chris@30 523
matthiasm@620 524 FlexiNote note(0);
matthiasm@620 525 FlexiNoteModel::PointList::iterator i;
Chris@30 526
Chris@30 527 for (i = points.begin(); i != points.end(); ++i) {
Chris@30 528
Chris@714 529 int y = getYForValue(v, i->value);
Chris@714 530 int h = NOTE_HEIGHT; // GF: larger notes
Chris@30 531
Chris@714 532 if (m_model->getValueQuantization() != 0.0) {
Chris@714 533 h = y - getYForValue(v, i->value + m_model->getValueQuantization());
Chris@714 534 if (h < NOTE_HEIGHT) h = NOTE_HEIGHT;
Chris@714 535 }
Chris@30 536
Chris@714 537 // GF: this is not quite correct
Chris@714 538 if (pos.y() >= y - 4 && pos.y() <= y + h) {
Chris@714 539 note = *i;
Chris@714 540 break;
Chris@714 541 }
Chris@30 542 }
Chris@30 543
Chris@30 544 if (i == points.end()) return tr("No local points");
Chris@30 545
Chris@30 546 RealTime rt = RealTime::frame2RealTime(note.frame,
Chris@714 547 m_model->getSampleRate());
Chris@30 548 RealTime rd = RealTime::frame2RealTime(note.duration,
Chris@714 549 m_model->getSampleRate());
Chris@30 550
Chris@101 551 QString pitchText;
Chris@101 552
Chris@101 553 if (shouldConvertMIDIToHz()) {
Chris@101 554
Chris@101 555 int mnote = lrintf(note.value);
Chris@101 556 int cents = lrintf((note.value - mnote) * 100);
Chris@101 557 float freq = Pitch::getFrequencyForPitch(mnote, cents);
Chris@544 558 pitchText = tr("%1 (%2, %3 Hz)")
Chris@544 559 .arg(Pitch::getPitchLabel(mnote, cents))
Chris@544 560 .arg(mnote)
Chris@544 561 .arg(freq);
Chris@101 562
Chris@701 563 } else if (getScaleUnits() == "Hz") {
Chris@101 564
Chris@544 565 pitchText = tr("%1 Hz (%2, %3)")
Chris@101 566 .arg(note.value)
Chris@544 567 .arg(Pitch::getPitchLabelForFrequency(note.value))
Chris@544 568 .arg(Pitch::getPitchForFrequency(note.value));
Chris@101 569
Chris@101 570 } else {
Chris@234 571 pitchText = tr("%1 %2")
Chris@701 572 .arg(note.value).arg(getScaleUnits());
Chris@101 573 }
Chris@101 574
Chris@30 575 QString text;
Chris@30 576
Chris@30 577 if (note.label == "") {
Chris@714 578 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nNo label"))
Chris@714 579 .arg(rt.toText(true).c_str())
Chris@714 580 .arg(pitchText)
Chris@714 581 .arg(rd.toText(true).c_str());
Chris@30 582 } else {
Chris@714 583 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nLabel:\t%4"))
Chris@714 584 .arg(rt.toText(true).c_str())
Chris@714 585 .arg(pitchText)
Chris@714 586 .arg(rd.toText(true).c_str())
Chris@714 587 .arg(note.label);
Chris@30 588 }
Chris@30 589
Chris@44 590 pos = QPoint(v->getXForFrame(note.frame),
Chris@714 591 getYForValue(v, note.value));
Chris@30 592 return text;
Chris@30 593 }
Chris@30 594
Chris@30 595 bool
matthiasm@620 596 FlexiNoteLayer::snapToFeatureFrame(View *v, int &frame,
Chris@805 597 int &resolution,
Chris@714 598 SnapType snap) const
Chris@30 599 {
Chris@30 600 if (!m_model) {
Chris@714 601 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
Chris@30 602 }
Chris@30 603
Chris@30 604 resolution = m_model->getResolution();
matthiasm@620 605 FlexiNoteModel::PointList points;
Chris@30 606
Chris@30 607 if (snap == SnapNeighbouring) {
gyorgyf@646 608
Chris@714 609 points = getLocalPoints(v, v->getXForFrame(frame));
Chris@714 610 if (points.empty()) return false;
Chris@714 611 frame = points.begin()->frame;
Chris@714 612 return true;
Chris@30 613 }
Chris@30 614
Chris@30 615 points = m_model->getPoints(frame, frame);
Chris@30 616 int snapped = frame;
Chris@30 617 bool found = false;
Chris@30 618
matthiasm@620 619 for (FlexiNoteModel::PointList::const_iterator i = points.begin();
Chris@714 620 i != points.end(); ++i) {
Chris@30 621
Chris@715 622 cerr << "FlexiNoteModel: point at " << i->frame << endl;
Chris@715 623
Chris@714 624 if (snap == SnapRight) {
Chris@30 625
Chris@714 626 if (i->frame > frame) {
Chris@714 627 snapped = i->frame;
Chris@714 628 found = true;
Chris@714 629 break;
Chris@715 630 } else if (i->frame + i->duration >= frame) {
Chris@715 631 snapped = i->frame + i->duration;
Chris@715 632 found = true;
Chris@715 633 break;
Chris@714 634 }
Chris@714 635
Chris@714 636 } else if (snap == SnapLeft) {
Chris@714 637
Chris@714 638 if (i->frame <= frame) {
Chris@714 639 snapped = i->frame;
Chris@714 640 found = true; // don't break, as the next may be better
Chris@714 641 } else {
Chris@714 642 break;
Chris@714 643 }
Chris@714 644
Chris@714 645 } else { // nearest
Chris@714 646
Chris@714 647 FlexiNoteModel::PointList::const_iterator j = i;
Chris@714 648 ++j;
Chris@714 649
Chris@714 650 if (j == points.end()) {
Chris@714 651
Chris@714 652 snapped = i->frame;
Chris@714 653 found = true;
Chris@714 654 break;
Chris@714 655
Chris@714 656 } else if (j->frame >= frame) {
Chris@714 657
Chris@714 658 if (j->frame - frame < frame - i->frame) {
Chris@714 659 snapped = j->frame;
Chris@714 660 } else {
Chris@714 661 snapped = i->frame;
Chris@714 662 }
Chris@714 663 found = true;
Chris@714 664 break;
Chris@714 665 }
gyorgyf@646 666 }
Chris@30 667 }
Chris@30 668
Chris@715 669 cerr << "snapToFeatureFrame: frame " << frame << " -> snapped " << snapped << ", found = " << found << endl;
Chris@715 670
Chris@30 671 frame = snapped;
Chris@30 672 return found;
Chris@30 673 }
Chris@30 674
Chris@101 675 void
matthiasm@620 676 FlexiNoteLayer::getScaleExtents(View *v, float &min, float &max, bool &log) const
Chris@30 677 {
Chris@101 678 min = 0.0;
Chris@101 679 max = 0.0;
Chris@101 680 log = false;
Chris@42 681
Chris@101 682 QString queryUnits;
Chris@101 683 if (shouldConvertMIDIToHz()) queryUnits = "Hz";
Chris@701 684 else queryUnits = getScaleUnits();
Chris@30 685
Chris@439 686 if (shouldAutoAlign()) {
Chris@30 687
Chris@101 688 if (!v->getValueExtents(queryUnits, min, max, log)) {
Chris@30 689
Chris@101 690 min = m_model->getValueMinimum();
Chris@101 691 max = m_model->getValueMaximum();
Chris@42 692
Chris@101 693 if (shouldConvertMIDIToHz()) {
Chris@101 694 min = Pitch::getFrequencyForPitch(lrintf(min));
Chris@101 695 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
Chris@101 696 }
Chris@42 697
Chris@667 698 #ifdef DEBUG_NOTE_LAYER
Chris@684 699 cerr << "FlexiNoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << endl;
Chris@667 700 #endif
Chris@105 701
Chris@101 702 } else if (log) {
Chris@101 703
Chris@197 704 LogRange::mapRange(min, max);
Chris@105 705
Chris@667 706 #ifdef DEBUG_NOTE_LAYER
Chris@684 707 cerr << "FlexiNoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << endl;
Chris@667 708 #endif
Chris@101 709 }
Chris@101 710
Chris@101 711 } else {
Chris@101 712
Chris@439 713 getDisplayExtents(min, max);
Chris@101 714
Chris@101 715 if (m_verticalScale == MIDIRangeScale) {
Chris@101 716 min = Pitch::getFrequencyForPitch(0);
matthiasm@623 717 max = Pitch::getFrequencyForPitch(70);
Chris@101 718 } else if (shouldConvertMIDIToHz()) {
Chris@101 719 min = Pitch::getFrequencyForPitch(lrintf(min));
Chris@101 720 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
Chris@101 721 }
Chris@101 722
Chris@101 723 if (m_verticalScale == LogScale || m_verticalScale == MIDIRangeScale) {
Chris@197 724 LogRange::mapRange(min, max);
Chris@101 725 log = true;
Chris@101 726 }
Chris@30 727 }
Chris@30 728
Chris@101 729 if (max == min) max = min + 1.0;
Chris@101 730 }
Chris@30 731
Chris@101 732 int
matthiasm@620 733 FlexiNoteLayer::getYForValue(View *v, float val) const
Chris@101 734 {
Chris@101 735 float min = 0.0, max = 0.0;
Chris@101 736 bool logarithmic = false;
Chris@101 737 int h = v->height();
Chris@101 738
Chris@101 739 getScaleExtents(v, min, max, logarithmic);
Chris@101 740
Chris@667 741 #ifdef DEBUG_NOTE_LAYER
Chris@684 742 cerr << "FlexiNoteLayer[" << this << "]::getYForValue(" << val << "): min = " << min << ", max = " << max << ", log = " << logarithmic << endl;
Chris@667 743 #endif
Chris@101 744
Chris@101 745 if (shouldConvertMIDIToHz()) {
Chris@101 746 val = Pitch::getFrequencyForPitch(lrintf(val),
Chris@101 747 lrintf((val - lrintf(val)) * 100));
Chris@667 748 #ifdef DEBUG_NOTE_LAYER
Chris@682 749 cerr << "shouldConvertMIDIToHz true, val now = " << val << endl;
Chris@667 750 #endif
Chris@101 751 }
Chris@101 752
Chris@101 753 if (logarithmic) {
Chris@197 754 val = LogRange::map(val);
Chris@667 755 #ifdef DEBUG_NOTE_LAYER
Chris@682 756 cerr << "logarithmic true, val now = " << val << endl;
Chris@667 757 #endif
Chris@101 758 }
Chris@101 759
Chris@101 760 int y = int(h - ((val - min) * h) / (max - min)) - 1;
Chris@667 761 #ifdef DEBUG_NOTE_LAYER
Chris@682 762 cerr << "y = " << y << endl;
Chris@667 763 #endif
Chris@101 764 return y;
Chris@30 765 }
Chris@30 766
Chris@30 767 float
matthiasm@620 768 FlexiNoteLayer::getValueForY(View *v, int y) const
Chris@30 769 {
Chris@101 770 float min = 0.0, max = 0.0;
Chris@101 771 bool logarithmic = false;
Chris@44 772 int h = v->height();
Chris@30 773
Chris@101 774 getScaleExtents(v, min, max, logarithmic);
Chris@101 775
Chris@101 776 float val = min + (float(h - y) * float(max - min)) / h;
Chris@101 777
Chris@101 778 if (logarithmic) {
Chris@197 779 val = powf(10.f, val);
Chris@101 780 }
Chris@101 781
Chris@101 782 if (shouldConvertMIDIToHz()) {
Chris@101 783 val = Pitch::getPitchForFrequency(val);
Chris@101 784 }
Chris@101 785
Chris@101 786 return val;
Chris@30 787 }
Chris@30 788
Chris@439 789 bool
matthiasm@620 790 FlexiNoteLayer::shouldAutoAlign() const
Chris@439 791 {
Chris@439 792 if (!m_model) return false;
Chris@439 793 return (m_verticalScale == AutoAlignScale);
Chris@439 794 }
Chris@439 795
Chris@30 796 void
matthiasm@620 797 FlexiNoteLayer::paint(View *v, QPainter &paint, QRect rect) const
Chris@30 798 {
Chris@30 799 if (!m_model || !m_model->isOK()) return;
Chris@30 800
Chris@30 801 int sampleRate = m_model->getSampleRate();
Chris@30 802 if (!sampleRate) return;
Chris@30 803
matthiasm@620 804 // Profiler profiler("FlexiNoteLayer::paint", true);
Chris@30 805
Chris@824 806 int x1 = rect.right();
Chris@806 807 int frame1 = v->getFrameForX(x1);
Chris@30 808
matthiasm@819 809 FlexiNoteModel::PointList points(m_model->getPoints(0, frame1));
Chris@30 810 if (points.empty()) return;
Chris@30 811
Chris@287 812 paint.setPen(getBaseQColor());
Chris@30 813
Chris@287 814 QColor brushColour(getBaseQColor());
Chris@30 815 brushColour.setAlpha(80);
Chris@30 816
matthiasm@620 817 // SVDEBUG << "FlexiNoteLayer::paint: resolution is "
gyorgyf@646 818 // << m_model->getResolution() << " frames" << endl;
Chris@30 819
Chris@30 820 float min = m_model->getValueMinimum();
Chris@30 821 float max = m_model->getValueMaximum();
Chris@30 822 if (max == min) max = min + 1.0;
Chris@30 823
Chris@30 824 QPoint localPos;
matthiasm@620 825 FlexiNoteModel::Point illuminatePoint(0);
Chris@551 826 bool shouldIlluminate = false;
Chris@30 827
Chris@44 828 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
Chris@551 829 shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(),
Chris@551 830 illuminatePoint);
Chris@30 831 }
Chris@30 832
Chris@30 833 paint.save();
Chris@30 834 paint.setRenderHint(QPainter::Antialiasing, false);
Chris@30 835
matthiasm@819 836 int noteNumber = 0;
matthiasm@819 837
matthiasm@620 838 for (FlexiNoteModel::PointList::const_iterator i = points.begin();
Chris@714 839 i != points.end(); ++i) {
Chris@30 840
matthiasm@819 841 ++noteNumber;
Chris@714 842 const FlexiNoteModel::Point &p(*i);
Chris@30 843
Chris@714 844 int x = v->getXForFrame(p.frame);
Chris@714 845 int y = getYForValue(v, p.value);
Chris@714 846 int w = v->getXForFrame(p.frame + p.duration) - x;
Chris@714 847 int h = NOTE_HEIGHT; //GF: larger notes
gyorgyf@646 848
Chris@714 849 if (m_model->getValueQuantization() != 0.0) {
Chris@714 850 h = y - getYForValue(v, p.value + m_model->getValueQuantization());
Chris@714 851 if (h < NOTE_HEIGHT) h = NOTE_HEIGHT; //GF: larger notes
Chris@714 852 }
Chris@30 853
Chris@714 854 if (w < 1) w = 1;
Chris@714 855 paint.setPen(getBaseQColor());
Chris@714 856 paint.setBrush(brushColour);
Chris@30 857
matthiasm@784 858 if (shouldIlluminate &&
matthiasm@784 859 // "illuminatePoint == p"
matthiasm@784 860 !FlexiNoteModel::Point::Comparator()(illuminatePoint, p) &&
matthiasm@784 861 !FlexiNoteModel::Point::Comparator()(p, illuminatePoint)) {
matthiasm@784 862
matthiasm@784 863 paint.drawLine(x, -1, x, v->height() + 1);
matthiasm@784 864 paint.drawLine(x+w, -1, x+w, v->height() + 1);
matthiasm@784 865
matthiasm@784 866 paint.setPen(v->getForeground());
matthiasm@784 867 // paint.setBrush(v->getForeground());
matthiasm@784 868
matthiasm@793 869 QString vlabel = QString("freq: %1%2").arg(p.value).arg(m_model->getScaleUnits());
matthiasm@793 870 // v->drawVisibleText(paint,
matthiasm@793 871 // x - paint.fontMetrics().width(vlabel) - 2,
matthiasm@793 872 // y + paint.fontMetrics().height()/2
matthiasm@793 873 // - paint.fontMetrics().descent(),
matthiasm@793 874 // vlabel, View::OutlinedText);
matthiasm@784 875 v->drawVisibleText(paint,
matthiasm@793 876 x,
matthiasm@793 877 y - h/2 - 2 - paint.fontMetrics().height()
matthiasm@784 878 - paint.fontMetrics().descent(),
matthiasm@784 879 vlabel, View::OutlinedText);
matthiasm@793 880
matthiasm@793 881 QString hlabel = "dur: " + QString(RealTime::frame2RealTime
matthiasm@793 882 (p.duration, m_model->getSampleRate()).toText(true).c_str());
matthiasm@784 883 v->drawVisibleText(paint,
matthiasm@784 884 x,
matthiasm@784 885 y - h/2 - paint.fontMetrics().descent() - 2,
matthiasm@784 886 hlabel, View::OutlinedText);
matthiasm@793 887
matthiasm@793 888 QString llabel = QString("%1").arg(p.label);
matthiasm@793 889 v->drawVisibleText(paint,
matthiasm@793 890 x,
matthiasm@793 891 y + h + 2 + paint.fontMetrics().descent(),
matthiasm@793 892 llabel, View::OutlinedText);
matthiasm@819 893 QString nlabel = QString("%1").arg(noteNumber);
matthiasm@819 894 v->drawVisibleText(paint,
matthiasm@819 895 x + paint.fontMetrics().averageCharWidth() / 2,
matthiasm@819 896 y + h/2 - paint.fontMetrics().descent(),
matthiasm@819 897 nlabel, View::OutlinedText);
matthiasm@784 898 }
gyorgyf@646 899
Chris@714 900 paint.drawRect(x, y - h/2, w, h);
Chris@30 901 }
Chris@30 902
Chris@30 903 paint.restore();
Chris@30 904 }
Chris@30 905
Chris@692 906 int
Chris@702 907 FlexiNoteLayer::getVerticalScaleWidth(View *v, bool, QPainter &paint) const
Chris@692 908 {
Chris@697 909 if (!m_model || shouldAutoAlign()) {
Chris@696 910 return 0;
Chris@701 911 } else {
Chris@701 912 if (m_verticalScale == LogScale || m_verticalScale == MIDIRangeScale) {
Chris@701 913 return LogNumericalScale().getWidth(v, paint) + 10; // for piano
Chris@701 914 } else {
Chris@701 915 return LinearNumericalScale().getWidth(v, paint);
Chris@701 916 }
Chris@696 917 }
Chris@692 918 }
Chris@692 919
Chris@692 920 void
Chris@695 921 FlexiNoteLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect) const
Chris@692 922 {
Chris@717 923 if (!m_model || m_model->getPoints().empty()) return;
Chris@701 924
Chris@701 925 QString unit;
Chris@701 926 float min, max;
Chris@701 927 bool logarithmic;
Chris@701 928
Chris@701 929 int w = getVerticalScaleWidth(v, false, paint);
Chris@701 930 int h = v->height();
Chris@701 931
Chris@701 932 getScaleExtents(v, min, max, logarithmic);
Chris@701 933
Chris@701 934 if (logarithmic) {
Chris@701 935 LogNumericalScale().paintVertical(v, this, paint, 0, min, max);
Chris@696 936 } else {
Chris@701 937 LinearNumericalScale().paintVertical(v, this, paint, 0, min, max);
Chris@701 938 }
Chris@701 939
Chris@701 940 if (logarithmic && (getScaleUnits() == "Hz")) {
Chris@696 941 PianoScale().paintPianoVertical
Chris@701 942 (v, paint, QRect(w - 10, 0, 10, h),
Chris@701 943 LogRange::unmap(min),
Chris@701 944 LogRange::unmap(max));
Chris@701 945 paint.drawLine(w, 0, w, h);
Chris@701 946 }
Chris@701 947
Chris@701 948 if (getScaleUnits() != "") {
Chris@701 949 int mw = w - 5;
Chris@701 950 paint.drawText(5,
Chris@701 951 5 + paint.fontMetrics().ascent(),
Chris@701 952 TextAbbrev::abbreviate(getScaleUnits(),
Chris@701 953 paint.fontMetrics(),
Chris@701 954 mw));
Chris@696 955 }
Chris@692 956 }
Chris@692 957
Chris@30 958 void
matthiasm@620 959 FlexiNoteLayer::drawStart(View *v, QMouseEvent *e)
Chris@30 960 {
matthiasm@620 961 // SVDEBUG << "FlexiNoteLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl;
Chris@30 962
Chris@30 963 if (!m_model) return;
Chris@30 964
Chris@806 965 int frame = v->getFrameForX(e->x());
Chris@30 966 if (frame < 0) frame = 0;
Chris@30 967 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@30 968
Chris@44 969 float value = getValueForY(v, e->y());
Chris@30 970
matthiasm@620 971 m_editingPoint = FlexiNoteModel::Point(frame, value, 0, 0.8, tr("New Point"));
Chris@30 972 m_originalPoint = m_editingPoint;
Chris@30 973
Chris@376 974 if (m_editingCommand) finish(m_editingCommand);
matthiasm@620 975 m_editingCommand = new FlexiNoteModel::EditCommand(m_model,
Chris@714 976 tr("Draw Point"));
Chris@30 977 m_editingCommand->addPoint(m_editingPoint);
Chris@30 978
Chris@30 979 m_editing = true;
Chris@30 980 }
Chris@30 981
Chris@30 982 void
matthiasm@620 983 FlexiNoteLayer::drawDrag(View *v, QMouseEvent *e)
Chris@30 984 {
matthiasm@620 985 // SVDEBUG << "FlexiNoteLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl;
Chris@30 986
Chris@30 987 if (!m_model || !m_editing) return;
Chris@30 988
Chris@806 989 int frame = v->getFrameForX(e->x());
Chris@30 990 if (frame < 0) frame = 0;
Chris@30 991 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@30 992
Chris@101 993 float newValue = getValueForY(v, e->y());
Chris@101 994
Chris@806 995 int newFrame = m_editingPoint.frame;
Chris@806 996 int newDuration = frame - newFrame;
Chris@101 997 if (newDuration < 0) {
Chris@101 998 newFrame = frame;
Chris@101 999 newDuration = -newDuration;
Chris@101 1000 } else if (newDuration == 0) {
Chris@101 1001 newDuration = 1;
Chris@101 1002 }
Chris@30 1003
Chris@30 1004 m_editingCommand->deletePoint(m_editingPoint);
Chris@101 1005 m_editingPoint.frame = newFrame;
Chris@101 1006 m_editingPoint.value = newValue;
Chris@101 1007 m_editingPoint.duration = newDuration;
Chris@30 1008 m_editingCommand->addPoint(m_editingPoint);
Chris@30 1009 }
Chris@30 1010
Chris@30 1011 void
matthiasm@620 1012 FlexiNoteLayer::drawEnd(View *, QMouseEvent *)
Chris@30 1013 {
matthiasm@620 1014 // SVDEBUG << "FlexiNoteLayer::drawEnd(" << e->x() << "," << e->y() << ")" << endl;
Chris@30 1015 if (!m_model || !m_editing) return;
Chris@376 1016 finish(m_editingCommand);
Chris@30 1017 m_editingCommand = 0;
Chris@30 1018 m_editing = false;
Chris@30 1019 }
Chris@30 1020
Chris@30 1021 void
matthiasm@620 1022 FlexiNoteLayer::eraseStart(View *v, QMouseEvent *e)
Chris@335 1023 {
Chris@335 1024 if (!m_model) return;
Chris@335 1025
Chris@550 1026 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return;
Chris@335 1027
Chris@335 1028 if (m_editingCommand) {
Chris@714 1029 finish(m_editingCommand);
Chris@714 1030 m_editingCommand = 0;
Chris@335 1031 }
Chris@335 1032
Chris@335 1033 m_editing = true;
Chris@335 1034 }
Chris@335 1035
Chris@335 1036 void
Chris@805 1037 FlexiNoteLayer::eraseDrag(View *, QMouseEvent *)
Chris@335 1038 {
Chris@335 1039 }
Chris@335 1040
Chris@335 1041 void
matthiasm@620 1042 FlexiNoteLayer::eraseEnd(View *v, QMouseEvent *e)
Chris@335 1043 {
Chris@335 1044 if (!m_model || !m_editing) return;
Chris@335 1045
Chris@335 1046 m_editing = false;
Chris@335 1047
matthiasm@620 1048 FlexiNoteModel::Point p(0);
Chris@550 1049 if (!getPointToDrag(v, e->x(), e->y(), p)) return;
Chris@550 1050 if (p.frame != m_editingPoint.frame || p.value != m_editingPoint.value) return;
Chris@550 1051
matthiasm@620 1052 m_editingCommand = new FlexiNoteModel::EditCommand(m_model, tr("Erase Point"));
Chris@335 1053
Chris@335 1054 m_editingCommand->deletePoint(m_editingPoint);
Chris@335 1055
Chris@376 1056 finish(m_editingCommand);
Chris@335 1057 m_editingCommand = 0;
Chris@335 1058 m_editing = false;
Chris@335 1059 }
Chris@335 1060
Chris@335 1061 void
matthiasm@620 1062 FlexiNoteLayer::editStart(View *v, QMouseEvent *e)
Chris@30 1063 {
matthiasm@620 1064 // SVDEBUG << "FlexiNoteLayer::editStart(" << e->x() << "," << e->y() << ")" << endl;
gyorgyf@635 1065 std::cerr << "FlexiNoteLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@30 1066
Chris@30 1067 if (!m_model) return;
Chris@30 1068
Chris@550 1069 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return;
matthiasm@651 1070 m_originalPoint = FlexiNote(m_editingPoint);
gyorgyf@649 1071
matthiasm@651 1072 if (m_editMode == RightBoundary) {
Chris@753 1073 m_dragPointX = v->getXForFrame(m_editingPoint.frame + m_editingPoint.duration);
gyorgyf@649 1074 } else {
gyorgyf@649 1075 m_dragPointX = v->getXForFrame(m_editingPoint.frame);
gyorgyf@649 1076 }
Chris@551 1077 m_dragPointY = getYForValue(v, m_editingPoint.value);
Chris@551 1078
Chris@30 1079 if (m_editingCommand) {
Chris@714 1080 finish(m_editingCommand);
Chris@714 1081 m_editingCommand = 0;
Chris@30 1082 }
Chris@30 1083
Chris@30 1084 m_editing = true;
Chris@551 1085 m_dragStartX = e->x();
Chris@551 1086 m_dragStartY = e->y();
matthiasm@651 1087
Chris@806 1088 int onset = m_originalPoint.frame;
Chris@806 1089 int offset = m_originalPoint.frame + m_originalPoint.duration - 1;
matthiasm@651 1090
matthiasm@651 1091 m_greatestLeftNeighbourFrame = -1;
Chris@806 1092 m_smallestRightNeighbourFrame = std::numeric_limits<int>::max();
matthiasm@651 1093
matthiasm@651 1094 for (FlexiNoteModel::PointList::const_iterator i = m_model->getPoints().begin();
matthiasm@651 1095 i != m_model->getPoints().end(); ++i) {
matthiasm@651 1096 FlexiNote currentNote = *i;
matthiasm@651 1097
matthiasm@651 1098 // left boundary
matthiasm@651 1099 if (currentNote.frame + currentNote.duration - 1 < onset) {
matthiasm@651 1100 m_greatestLeftNeighbourFrame = currentNote.frame + currentNote.duration - 1;
matthiasm@651 1101 }
matthiasm@651 1102
matthiasm@651 1103 // right boundary
matthiasm@651 1104 if (currentNote.frame > offset) {
matthiasm@651 1105 m_smallestRightNeighbourFrame = currentNote.frame;
matthiasm@651 1106 break;
matthiasm@651 1107 }
matthiasm@651 1108 }
Chris@753 1109 std::cerr << "editStart: mode is " << m_editMode << ", note frame: " << onset << ", left boundary: " << m_greatestLeftNeighbourFrame << ", right boundary: " << m_smallestRightNeighbourFrame << std::endl;
Chris@30 1110 }
Chris@30 1111
Chris@30 1112 void
matthiasm@620 1113 FlexiNoteLayer::editDrag(View *v, QMouseEvent *e)
Chris@30 1114 {
matthiasm@620 1115 // SVDEBUG << "FlexiNoteLayer::editDrag(" << e->x() << "," << e->y() << ")" << endl;
gyorgyf@635 1116 std::cerr << "FlexiNoteLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@30 1117
Chris@30 1118 if (!m_model || !m_editing) return;
Chris@30 1119
Chris@551 1120 int xdist = e->x() - m_dragStartX;
Chris@551 1121 int ydist = e->y() - m_dragStartY;
Chris@551 1122 int newx = m_dragPointX + xdist;
Chris@551 1123 int newy = m_dragPointY + ydist;
Chris@551 1124
Chris@806 1125 int dragFrame = v->getFrameForX(newx);
matthiasm@657 1126 if (dragFrame < 0) dragFrame = 0;
matthiasm@657 1127 dragFrame = dragFrame / m_model->getResolution() * m_model->getResolution();
matthiasm@651 1128
Chris@551 1129 float value = getValueForY(v, newy);
Chris@30 1130
Chris@30 1131 if (!m_editingCommand) {
Chris@714 1132 m_editingCommand = new FlexiNoteModel::EditCommand(m_model,
Chris@714 1133 tr("Drag Point"));
Chris@30 1134 }
Chris@30 1135
Chris@30 1136 m_editingCommand->deletePoint(m_editingPoint);
matthiasm@651 1137
matthiasm@651 1138 std::cerr << "edit mode: " << m_editMode << std::endl;
matthiasm@657 1139
matthiasm@651 1140 switch (m_editMode) {
Chris@714 1141 case LeftBoundary : {
Chris@714 1142 // left
Chris@714 1143 if (m_intelligentActions && dragFrame <= m_greatestLeftNeighbourFrame) dragFrame = m_greatestLeftNeighbourFrame + 1;
Chris@714 1144 // right
Chris@714 1145 if (m_intelligentActions && dragFrame >= m_originalPoint.frame + m_originalPoint.duration) {
Chris@714 1146 dragFrame = m_originalPoint.frame + m_originalPoint.duration - 1;
matthiasm@651 1147 }
Chris@714 1148 m_editingPoint.frame = dragFrame;
Chris@714 1149 m_editingPoint.duration = m_originalPoint.frame - dragFrame + m_originalPoint.duration;
Chris@714 1150 break;
Chris@714 1151 }
Chris@714 1152 case RightBoundary : {
Chris@714 1153 // left
Chris@714 1154 if (m_intelligentActions && dragFrame <= m_greatestLeftNeighbourFrame) dragFrame = m_greatestLeftNeighbourFrame + 1;
Chris@714 1155 if (m_intelligentActions && dragFrame >= m_smallestRightNeighbourFrame) dragFrame = m_smallestRightNeighbourFrame - 1;
Chris@714 1156 m_editingPoint.duration = dragFrame - m_originalPoint.frame + 1;
Chris@714 1157 break;
Chris@714 1158 }
Chris@714 1159 case DragNote : {
Chris@714 1160 // left
Chris@714 1161 if (m_intelligentActions && dragFrame <= m_greatestLeftNeighbourFrame) dragFrame = m_greatestLeftNeighbourFrame + 1;
Chris@714 1162 // right
Chris@714 1163 if (m_intelligentActions && dragFrame + m_originalPoint.duration >= m_smallestRightNeighbourFrame) {
Chris@714 1164 dragFrame = m_smallestRightNeighbourFrame - m_originalPoint.duration;
matthiasm@651 1165 }
Chris@714 1166 m_editingPoint.frame = dragFrame;
Chris@714 1167 m_editingPoint.value = value;
Chris@714 1168 break;
Chris@714 1169 }
Chris@805 1170 case SplitNote: // nothing
Chris@805 1171 break;
gyorgyf@649 1172 }
matthiasm@764 1173 updateNoteValue(v, m_editingPoint);
Chris@30 1174 m_editingCommand->addPoint(m_editingPoint);
gyorgyf@649 1175 std::cerr << "added new point(" << m_editingPoint.frame << "," << m_editingPoint.duration << ")" << std::endl;
gyorgyf@649 1176
Chris@30 1177 }
Chris@30 1178
Chris@30 1179 void
Chris@805 1180 FlexiNoteLayer::editEnd(View *, QMouseEvent *e)
Chris@30 1181 {
matthiasm@620 1182 // SVDEBUG << "FlexiNoteLayer::editEnd(" << e->x() << "," << e->y() << ")" << endl;
gyorgyf@635 1183 std::cerr << "FlexiNoteLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
matthiasm@656 1184
Chris@30 1185 if (!m_model || !m_editing) return;
Chris@30 1186
Chris@30 1187 if (m_editingCommand) {
Chris@30 1188
Chris@714 1189 QString newName = m_editingCommand->getName();
Chris@30 1190
Chris@714 1191 if (m_editingPoint.frame != m_originalPoint.frame) {
Chris@714 1192 if (m_editingPoint.value != m_originalPoint.value) {
Chris@714 1193 newName = tr("Edit Point");
Chris@714 1194 } else {
Chris@714 1195 newName = tr("Relocate Point");
Chris@714 1196 }
gyorgyf@646 1197 } else {
Chris@714 1198 newName = tr("Change Point Value");
gyorgyf@646 1199 }
Chris@30 1200
Chris@714 1201 m_editingCommand->setName(newName);
Chris@714 1202 finish(m_editingCommand);
Chris@30 1203 }
Chris@30 1204
Chris@30 1205 m_editingCommand = 0;
Chris@30 1206 m_editing = false;
Chris@30 1207 }
Chris@30 1208
gyorgyf@635 1209 void
gyorgyf@635 1210 FlexiNoteLayer::splitStart(View *v, QMouseEvent *e)
gyorgyf@635 1211 {
gyorgyf@646 1212 // GF: note splitting starts (!! remove printing soon)
gyorgyf@646 1213 std::cerr << "splitStart" << std::endl;
gyorgyf@646 1214 if (!m_model) return;
gyorgyf@635 1215
gyorgyf@635 1216 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return;
gyorgyf@635 1217 // m_originalPoint = m_editingPoint;
gyorgyf@635 1218 //
gyorgyf@635 1219 // m_dragPointX = v->getXForFrame(m_editingPoint.frame);
gyorgyf@635 1220 // m_dragPointY = getYForValue(v, m_editingPoint.value);
gyorgyf@635 1221
gyorgyf@635 1222 if (m_editingCommand) {
Chris@714 1223 finish(m_editingCommand);
Chris@714 1224 m_editingCommand = 0;
gyorgyf@635 1225 }
gyorgyf@635 1226
gyorgyf@635 1227 m_editing = true;
gyorgyf@635 1228 m_dragStartX = e->x();
gyorgyf@635 1229 m_dragStartY = e->y();
gyorgyf@635 1230
gyorgyf@635 1231 }
gyorgyf@635 1232
gyorgyf@635 1233 void
gyorgyf@635 1234 FlexiNoteLayer::splitEnd(View *v, QMouseEvent *e)
gyorgyf@635 1235 {
gyorgyf@646 1236 // GF: note splitting ends. (!! remove printing soon)
gyorgyf@646 1237 std::cerr << "splitEnd" << std::endl;
matthiasm@651 1238 if (!m_model || !m_editing || m_editMode != SplitNote) return;
gyorgyf@635 1239
gyorgyf@635 1240 int xdist = e->x() - m_dragStartX;
gyorgyf@635 1241 int ydist = e->y() - m_dragStartY;
gyorgyf@635 1242 if (xdist != 0 || ydist != 0) {
gyorgyf@646 1243 std::cerr << "mouse moved" << std::endl;
gyorgyf@635 1244 return;
gyorgyf@635 1245 }
gyorgyf@635 1246
Chris@806 1247 int frame = v->getFrameForX(e->x());
gyorgyf@635 1248
Chris@753 1249 splitNotesAt(v, frame, e);
Chris@746 1250 }
Chris@746 1251
Chris@746 1252 void
Chris@746 1253 FlexiNoteLayer::splitNotesAt(View *v, int frame)
Chris@746 1254 {
Chris@753 1255 splitNotesAt(v, frame, 0);
Chris@753 1256 }
Chris@753 1257
Chris@753 1258 void
Chris@753 1259 FlexiNoteLayer::splitNotesAt(View *v, int frame, QMouseEvent *e)
Chris@753 1260 {
Chris@746 1261 FlexiNoteModel::PointList onPoints = m_model->getPoints(frame);
Chris@746 1262 if (onPoints.empty()) return;
Chris@746 1263
Chris@746 1264 FlexiNote note(*onPoints.begin());
gyorgyf@635 1265
gyorgyf@635 1266 FlexiNoteModel::EditCommand *command = new FlexiNoteModel::EditCommand
gyorgyf@635 1267 (m_model, tr("Edit Point"));
gyorgyf@635 1268 command->deletePoint(note);
Chris@753 1269
Chris@753 1270 if (!e || !(e->modifiers() & Qt::ShiftModifier)) {
Chris@753 1271
Chris@753 1272 int gap = 0; // MM: I prefer a gap of 0, but we can decide later
Chris@753 1273
Chris@753 1274 FlexiNote newNote1(note.frame, note.value,
Chris@753 1275 frame - note.frame - gap,
Chris@753 1276 note.level, note.label);
Chris@753 1277
Chris@753 1278 FlexiNote newNote2(frame, note.value,
Chris@753 1279 note.duration - newNote1.duration,
Chris@753 1280 note.level, note.label);
Chris@747 1281
Chris@753 1282 if (m_intelligentActions) {
Chris@753 1283 if (updateNoteValue(v, newNote1)) {
Chris@753 1284 command->addPoint(newNote1);
Chris@753 1285 }
Chris@753 1286 if (updateNoteValue(v, newNote2)) {
Chris@753 1287 command->addPoint(newNote2);
Chris@753 1288 }
Chris@753 1289 } else {
Chris@747 1290 command->addPoint(newNote1);
Chris@747 1291 command->addPoint(newNote2);
Chris@747 1292 }
Chris@747 1293 }
Chris@746 1294
gyorgyf@635 1295 finish(command);
gyorgyf@646 1296 }
gyorgyf@646 1297
gyorgyf@655 1298 void
matthiasm@660 1299 FlexiNoteLayer::addNote(View *v, QMouseEvent *e)
matthiasm@660 1300 {
matthiasm@660 1301 std::cerr << "addNote" << std::endl;
matthiasm@660 1302 if (!m_model) return;
matthiasm@660 1303
Chris@806 1304 int duration = 10000;
matthiasm@660 1305
Chris@806 1306 int frame = v->getFrameForX(e->x());
matthiasm@660 1307 float value = getValueForY(v, e->y());
matthiasm@660 1308
matthiasm@792 1309 FlexiNoteModel::PointList noteList = m_model->getPoints();
matthiasm@792 1310
matthiasm@660 1311 if (m_intelligentActions) {
Chris@806 1312 int smallestRightNeighbourFrame = 0;
matthiasm@792 1313 for (FlexiNoteModel::PointList::const_iterator i = noteList.begin();
matthiasm@792 1314 i != noteList.end(); ++i) {
matthiasm@660 1315 FlexiNote currentNote = *i;
matthiasm@660 1316 if (currentNote.frame > frame) {
matthiasm@660 1317 smallestRightNeighbourFrame = currentNote.frame;
matthiasm@660 1318 break;
matthiasm@660 1319 }
matthiasm@660 1320 }
matthiasm@792 1321 if (smallestRightNeighbourFrame > 0) {
matthiasm@792 1322 duration = std::min(smallestRightNeighbourFrame - frame + 1, duration);
matthiasm@792 1323 duration = (duration > 0) ? duration : 0;
matthiasm@792 1324 }
matthiasm@660 1325 }
matthiasm@660 1326
matthiasm@660 1327 if (!m_intelligentActions ||
Chris@746 1328 (m_model->getPoints(frame).empty() && duration > 0)) {
matthiasm@660 1329 FlexiNote newNote(frame, value, duration, 100, "new note");
matthiasm@660 1330 FlexiNoteModel::EditCommand *command = new FlexiNoteModel::EditCommand
Chris@714 1331 (m_model, tr("Add Point"));
matthiasm@660 1332 command->addPoint(newNote);
matthiasm@660 1333 finish(command);
matthiasm@660 1334 }
matthiasm@660 1335 }
matthiasm@660 1336
Chris@745 1337 SparseTimeValueModel *
Chris@745 1338 FlexiNoteLayer::getAssociatedPitchModel(View *v) const
Chris@745 1339 {
Chris@745 1340 // Better than we used to do, but still not very satisfactory
Chris@745 1341
Chris@746 1342 cerr << "FlexiNoteLayer::getAssociatedPitchModel()" << endl;
Chris@746 1343
Chris@745 1344 for (int i = 0; i < v->getLayerCount(); ++i) {
Chris@745 1345 Layer *layer = v->getLayer(i);
Chris@795 1346 if (layer &&
Chris@748 1347 layer->getLayerPresentationName() != "candidate") {
Chris@746 1348 cerr << "FlexiNoteLayer::getAssociatedPitchModel: looks like our layer is " << layer << endl;
Chris@745 1349 SparseTimeValueModel *model = qobject_cast<SparseTimeValueModel *>
Chris@745 1350 (layer->getModel());
Chris@746 1351 cerr << "FlexiNoteLayer::getAssociatedPitchModel: and its model is " << model << endl;
Chris@745 1352 if (model && model->getScaleUnits() == "Hz") {
Chris@746 1353 cerr << "FlexiNoteLayer::getAssociatedPitchModel: it's good, returning " << model << endl;
Chris@745 1354 return model;
Chris@745 1355 }
Chris@745 1356 }
Chris@745 1357 }
Chris@745 1358 return 0;
Chris@745 1359 }
matthiasm@660 1360
matthiasm@660 1361 void
Chris@746 1362 FlexiNoteLayer::snapSelectedNotesToPitchTrack(View *v, Selection s)
Chris@746 1363 {
Chris@746 1364 if (!m_model) return;
Chris@746 1365
Chris@746 1366 FlexiNoteModel::PointList points =
Chris@746 1367 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@746 1368
Chris@746 1369 FlexiNoteModel::EditCommand *command = new FlexiNoteModel::EditCommand
Chris@746 1370 (m_model, tr("Snap Notes"));
Chris@746 1371
Chris@746 1372 cerr << "snapSelectedNotesToPitchTrack: selection is from " << s.getStartFrame() << " to " << s.getEndFrame() << endl;
Chris@746 1373
Chris@746 1374 for (FlexiNoteModel::PointList::iterator i = points.begin();
Chris@746 1375 i != points.end(); ++i) {
Chris@746 1376
Chris@746 1377 FlexiNote note(*i);
Chris@746 1378
Chris@746 1379 cerr << "snapSelectedNotesToPitchTrack: looking at note from " << note.frame << " to " << note.frame + note.duration << endl;
Chris@746 1380
Chris@748 1381 if (!s.contains(note.frame) &&
Chris@746 1382 !s.contains(note.frame + note.duration - 1)) {
Chris@746 1383 continue;
Chris@746 1384 }
Chris@746 1385
matthiasm@773 1386 cerr << "snapSelectedNotesToPitchTrack: making new note" << endl;
Chris@746 1387 FlexiNote newNote(note);
Chris@746 1388
Chris@746 1389 command->deletePoint(note);
Chris@746 1390
matthiasm@775 1391 if (updateNoteValue(v, newNote)) {
matthiasm@775 1392 command->addPoint(newNote);
matthiasm@775 1393 }
Chris@746 1394 }
Chris@747 1395
Chris@746 1396 finish(command);
Chris@746 1397 }
Chris@746 1398
Chris@746 1399 void
Chris@749 1400 FlexiNoteLayer::mergeNotes(View *v, Selection s, bool inclusive)
Chris@747 1401 {
Chris@747 1402 FlexiNoteModel::PointList points =
Chris@747 1403 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@747 1404
Chris@747 1405 FlexiNoteModel::PointList::iterator i = points.begin();
Chris@749 1406 if (inclusive) {
Chris@749 1407 while (i != points.end() && i->frame + i->duration < s.getStartFrame()) {
Chris@749 1408 ++i;
Chris@749 1409 }
Chris@749 1410 } else {
Chris@749 1411 while (i != points.end() && i->frame < s.getStartFrame()) {
Chris@749 1412 ++i;
Chris@749 1413 }
Chris@747 1414 }
Chris@749 1415
Chris@747 1416 if (i == points.end()) return;
Chris@747 1417
Chris@747 1418 FlexiNoteModel::EditCommand *command =
Chris@747 1419 new FlexiNoteModel::EditCommand(m_model, tr("Merge Notes"));
Chris@747 1420
Chris@747 1421 FlexiNote newNote(*i);
Chris@747 1422
Chris@747 1423 while (i != points.end()) {
Chris@747 1424
Chris@749 1425 if (inclusive) {
Chris@749 1426 if (i->frame >= s.getEndFrame()) break;
Chris@749 1427 } else {
Chris@749 1428 if (i->frame + i->duration > s.getEndFrame()) break;
Chris@749 1429 }
Chris@747 1430
Chris@747 1431 newNote.duration = i->frame + i->duration - newNote.frame;
Chris@747 1432 command->deletePoint(*i);
Chris@747 1433
Chris@747 1434 ++i;
Chris@747 1435 }
Chris@747 1436
Chris@747 1437 updateNoteValue(v, newNote);
Chris@747 1438 command->addPoint(newNote);
Chris@747 1439 finish(command);
Chris@747 1440 }
Chris@747 1441
Chris@747 1442 bool
gyorgyf@655 1443 FlexiNoteLayer::updateNoteValue(View *v, FlexiNoteModel::Point &note) const
gyorgyf@655 1444 {
Chris@745 1445 SparseTimeValueModel *model = getAssociatedPitchModel(v);
Chris@747 1446 if (!model) return false;
gyorgyf@655 1447
gyorgyf@655 1448 std::cerr << model->getTypeName() << std::endl;
gyorgyf@655 1449
Chris@747 1450 SparseModel<TimeValuePoint>::PointList dataPoints =
Chris@747 1451 model->getPoints(note.frame, note.frame + note.duration);
Chris@746 1452
Chris@746 1453 std::cerr << "frame " << note.frame << ": " << dataPoints.size() << " candidate points" << std::endl;
Chris@746 1454
Chris@747 1455 if (dataPoints.empty()) return false;
Chris@746 1456
Chris@714 1457 std::vector<float> pitchValues;
gyorgyf@655 1458
Chris@747 1459 for (SparseModel<TimeValuePoint>::PointList::const_iterator i =
Chris@747 1460 dataPoints.begin(); i != dataPoints.end(); ++i) {
Chris@747 1461 if (i->frame >= note.frame &&
Chris@747 1462 i->frame < note.frame + note.duration) {
Chris@748 1463 pitchValues.push_back(i->value);
Chris@747 1464 }
gyorgyf@655 1465 }
Chris@747 1466
Chris@747 1467 if (pitchValues.empty()) return false;
Chris@747 1468
gyorgyf@655 1469 sort(pitchValues.begin(), pitchValues.end());
Chris@805 1470 int size = pitchValues.size();
gyorgyf@655 1471 double median;
gyorgyf@655 1472
gyorgyf@655 1473 if (size % 2 == 0) {
gyorgyf@655 1474 median = (pitchValues[size/2 - 1] + pitchValues[size/2]) / 2;
gyorgyf@655 1475 } else {
gyorgyf@655 1476 median = pitchValues[size/2];
gyorgyf@655 1477 }
gyorgyf@655 1478
gyorgyf@655 1479 note.value = median;
Chris@747 1480
Chris@747 1481 return true;
gyorgyf@655 1482 }
gyorgyf@655 1483
gyorgyf@646 1484 void
gyorgyf@646 1485 FlexiNoteLayer::mouseMoveEvent(View *v, QMouseEvent *e)
gyorgyf@646 1486 {
gyorgyf@646 1487 // GF: context sensitive cursors
gyorgyf@646 1488 // v->setCursor(Qt::ArrowCursor);
gyorgyf@646 1489 FlexiNoteModel::Point note(0);
gyorgyf@646 1490 if (!getNoteToEdit(v, e->x(), e->y(), note)) {
gyorgyf@646 1491 // v->setCursor(Qt::UpArrowCursor);
gyorgyf@646 1492 return;
gyorgyf@646 1493 }
gyorgyf@646 1494
gyorgyf@646 1495 bool closeToLeft = false, closeToRight = false, closeToTop = false, closeToBottom = false;
gyorgyf@646 1496 getRelativeMousePosition(v, note, e->x(), e->y(), closeToLeft, closeToRight, closeToTop, closeToBottom);
gyorgyf@646 1497 // if (!closeToLeft) return;
gyorgyf@646 1498 // if (closeToTop) v->setCursor(Qt::SizeVerCursor);
gyorgyf@649 1499
matthiasm@651 1500 if (closeToLeft) { v->setCursor(Qt::SizeHorCursor); m_editMode = LeftBoundary; return; }
matthiasm@651 1501 if (closeToRight) { v->setCursor(Qt::SizeHorCursor); m_editMode = RightBoundary; return; }
matthiasm@651 1502 if (closeToTop) { v->setCursor(Qt::CrossCursor); m_editMode = DragNote; return; }
matthiasm@651 1503 if (closeToBottom) { v->setCursor(Qt::UpArrowCursor); m_editMode = SplitNote; return; }
gyorgyf@649 1504
gyorgyf@646 1505 v->setCursor(Qt::ArrowCursor);
gyorgyf@646 1506
matthiasm@784 1507 std::cerr << "Mouse moved in edit mode over FlexiNoteLayer" << std::endl;
gyorgyf@646 1508 // v->setCursor(Qt::SizeHorCursor);
gyorgyf@646 1509
gyorgyf@646 1510 }
gyorgyf@646 1511
gyorgyf@646 1512 void
gyorgyf@646 1513 FlexiNoteLayer::getRelativeMousePosition(View *v, FlexiNoteModel::Point &note, int x, int y, bool &closeToLeft, bool &closeToRight, bool &closeToTop, bool &closeToBottom) const
gyorgyf@646 1514 {
gyorgyf@649 1515 // GF: TODO: consoloidate the tolerance values
gyorgyf@646 1516 if (!m_model) return;
gyorgyf@646 1517
matthiasm@651 1518 int ctol = 0;
gyorgyf@646 1519 int noteStartX = v->getXForFrame(note.frame);
gyorgyf@646 1520 int noteEndX = v->getXForFrame(note.frame + note.duration);
gyorgyf@646 1521 int noteValueY = getYForValue(v,note.value);
gyorgyf@646 1522 int noteStartY = noteValueY - (NOTE_HEIGHT / 2);
gyorgyf@646 1523 int noteEndY = noteValueY + (NOTE_HEIGHT / 2);
gyorgyf@646 1524
gyorgyf@646 1525 bool closeToNote = false;
gyorgyf@646 1526
gyorgyf@646 1527 if (y >= noteStartY-ctol && y <= noteEndY+ctol && x >= noteStartX-ctol && x <= noteEndX+ctol) closeToNote = true;
gyorgyf@646 1528 if (!closeToNote) return;
gyorgyf@646 1529
matthiasm@651 1530 int tol = NOTE_HEIGHT / 2;
gyorgyf@646 1531
gyorgyf@646 1532 if (x >= noteStartX - tol && x <= noteStartX + tol) closeToLeft = true;
gyorgyf@646 1533 if (x >= noteEndX - tol && x <= noteEndX + tol) closeToRight = true;
gyorgyf@646 1534 if (y >= noteStartY - tol && y <= noteStartY + tol) closeToTop = true;
gyorgyf@646 1535 if (y >= noteEndY - tol && y <= noteEndY + tol) closeToBottom = true;
Chris@688 1536
Chris@688 1537 // cerr << "FlexiNoteLayer::getRelativeMousePosition: close to: left " << closeToLeft << " right " << closeToRight << " top " << closeToTop << " bottom " << closeToBottom << endl;
gyorgyf@635 1538 }
gyorgyf@635 1539
gyorgyf@635 1540
Chris@255 1541 bool
matthiasm@620 1542 FlexiNoteLayer::editOpen(View *v, QMouseEvent *e)
Chris@70 1543 {
gyorgyf@633 1544 std::cerr << "Opening note editor dialog" << std::endl;
Chris@255 1545 if (!m_model) return false;
Chris@70 1546
matthiasm@620 1547 FlexiNoteModel::Point note(0);
Chris@550 1548 if (!getPointToDrag(v, e->x(), e->y(), note)) return false;
Chris@550 1549
matthiasm@620 1550 // FlexiNoteModel::Point note = *points.begin();
Chris@70 1551
Chris@70 1552 ItemEditDialog *dialog = new ItemEditDialog
Chris@70 1553 (m_model->getSampleRate(),
Chris@70 1554 ItemEditDialog::ShowTime |
Chris@70 1555 ItemEditDialog::ShowDuration |
Chris@70 1556 ItemEditDialog::ShowValue |
Chris@100 1557 ItemEditDialog::ShowText,
Chris@701 1558 getScaleUnits());
Chris@70 1559
Chris@70 1560 dialog->setFrameTime(note.frame);
Chris@70 1561 dialog->setValue(note.value);
Chris@70 1562 dialog->setFrameDuration(note.duration);
Chris@70 1563 dialog->setText(note.label);
Chris@70 1564
Chris@70 1565 if (dialog->exec() == QDialog::Accepted) {
Chris@70 1566
matthiasm@620 1567 FlexiNoteModel::Point newNote = note;
Chris@70 1568 newNote.frame = dialog->getFrameTime();
Chris@70 1569 newNote.value = dialog->getValue();
Chris@70 1570 newNote.duration = dialog->getFrameDuration();
Chris@70 1571 newNote.label = dialog->getText();
Chris@70 1572
matthiasm@620 1573 FlexiNoteModel::EditCommand *command = new FlexiNoteModel::EditCommand
Chris@70 1574 (m_model, tr("Edit Point"));
Chris@70 1575 command->deletePoint(note);
Chris@70 1576 command->addPoint(newNote);
Chris@376 1577 finish(command);
Chris@70 1578 }
Chris@70 1579
Chris@70 1580 delete dialog;
Chris@255 1581 return true;
Chris@70 1582 }
Chris@70 1583
Chris@70 1584 void
Chris@805 1585 FlexiNoteLayer::moveSelection(Selection s, int newStartFrame)
Chris@43 1586 {
Chris@99 1587 if (!m_model) return;
Chris@99 1588
matthiasm@620 1589 FlexiNoteModel::EditCommand *command =
Chris@714 1590 new FlexiNoteModel::EditCommand(m_model, tr("Drag Selection"));
Chris@43 1591
matthiasm@620 1592 FlexiNoteModel::PointList points =
Chris@714 1593 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@43 1594
matthiasm@620 1595 for (FlexiNoteModel::PointList::iterator i = points.begin();
Chris@714 1596 i != points.end(); ++i) {
Chris@43 1597
Chris@714 1598 if (s.contains(i->frame)) {
Chris@714 1599 FlexiNoteModel::Point newPoint(*i);
Chris@714 1600 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
Chris@714 1601 command->deletePoint(*i);
Chris@714 1602 command->addPoint(newPoint);
Chris@714 1603 }
Chris@43 1604 }
Chris@43 1605
Chris@376 1606 finish(command);
Chris@43 1607 }
Chris@43 1608
Chris@43 1609 void
matthiasm@620 1610 FlexiNoteLayer::resizeSelection(Selection s, Selection newSize)
Chris@43 1611 {
Chris@99 1612 if (!m_model) return;
Chris@99 1613
matthiasm@620 1614 FlexiNoteModel::EditCommand *command =
Chris@714 1615 new FlexiNoteModel::EditCommand(m_model, tr("Resize Selection"));
Chris@43 1616
matthiasm@620 1617 FlexiNoteModel::PointList points =
Chris@714 1618 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@43 1619
Chris@43 1620 double ratio =
Chris@714 1621 double(newSize.getEndFrame() - newSize.getStartFrame()) /
Chris@714 1622 double(s.getEndFrame() - s.getStartFrame());
Chris@43 1623
matthiasm@620 1624 for (FlexiNoteModel::PointList::iterator i = points.begin();
Chris@714 1625 i != points.end(); ++i) {
Chris@43 1626
Chris@714 1627 if (s.contains(i->frame)) {
Chris@43 1628
Chris@714 1629 double targetStart = i->frame;
Chris@714 1630 targetStart = newSize.getStartFrame() +
Chris@714 1631 double(targetStart - s.getStartFrame()) * ratio;
Chris@43 1632
Chris@714 1633 double targetEnd = i->frame + i->duration;
Chris@714 1634 targetEnd = newSize.getStartFrame() +
Chris@714 1635 double(targetEnd - s.getStartFrame()) * ratio;
Chris@43 1636
Chris@714 1637 FlexiNoteModel::Point newPoint(*i);
Chris@714 1638 newPoint.frame = lrint(targetStart);
Chris@714 1639 newPoint.duration = lrint(targetEnd - targetStart);
Chris@714 1640 command->deletePoint(*i);
Chris@714 1641 command->addPoint(newPoint);
Chris@714 1642 }
Chris@43 1643 }
Chris@43 1644
Chris@376 1645 finish(command);
Chris@43 1646 }
Chris@43 1647
Chris@76 1648 void
matthiasm@620 1649 FlexiNoteLayer::deleteSelection(Selection s)
Chris@76 1650 {
Chris@99 1651 if (!m_model) return;
Chris@99 1652
matthiasm@620 1653 FlexiNoteModel::EditCommand *command =
Chris@714 1654 new FlexiNoteModel::EditCommand(m_model, tr("Delete Selected Points"));
Chris@76 1655
matthiasm@620 1656 FlexiNoteModel::PointList points =
Chris@714 1657 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@76 1658
matthiasm@620 1659 for (FlexiNoteModel::PointList::iterator i = points.begin();
Chris@714 1660 i != points.end(); ++i) {
Chris@76 1661
Chris@76 1662 if (s.contains(i->frame)) {
Chris@76 1663 command->deletePoint(*i);
Chris@76 1664 }
Chris@76 1665 }
Chris@76 1666
Chris@376 1667 finish(command);
Chris@76 1668 }
Chris@76 1669
Chris@76 1670 void
matthiasm@784 1671 FlexiNoteLayer::deleteSelectionInclusive(Selection s)
matthiasm@784 1672 {
matthiasm@784 1673 if (!m_model) return;
matthiasm@784 1674
matthiasm@784 1675 FlexiNoteModel::EditCommand *command =
matthiasm@784 1676 new FlexiNoteModel::EditCommand(m_model, tr("Delete Selected Points"));
matthiasm@784 1677
matthiasm@784 1678 FlexiNoteModel::PointList points =
matthiasm@784 1679 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
matthiasm@784 1680
matthiasm@784 1681 for (FlexiNoteModel::PointList::iterator i = points.begin();
matthiasm@784 1682 i != points.end(); ++i) {
matthiasm@796 1683 bool overlap = !(
matthiasm@799 1684 ((s.getStartFrame() <= i->frame) && (s.getEndFrame() <= i->frame)) || // selection is left of note
matthiasm@799 1685 ((s.getStartFrame() >= (i->frame+i->duration)) && (s.getEndFrame() >= (i->frame+i->duration))) // selection is right of note
matthiasm@796 1686 );
matthiasm@784 1687 if (overlap) {
matthiasm@784 1688 command->deletePoint(*i);
matthiasm@784 1689 }
matthiasm@784 1690 }
matthiasm@784 1691
matthiasm@784 1692 finish(command);
matthiasm@784 1693 }
matthiasm@784 1694
matthiasm@784 1695 void
matthiasm@620 1696 FlexiNoteLayer::copy(View *v, Selection s, Clipboard &to)
Chris@76 1697 {
Chris@99 1698 if (!m_model) return;
Chris@99 1699
matthiasm@620 1700 FlexiNoteModel::PointList points =
Chris@714 1701 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@76 1702
matthiasm@620 1703 for (FlexiNoteModel::PointList::iterator i = points.begin();
Chris@714 1704 i != points.end(); ++i) {
Chris@714 1705 if (s.contains(i->frame)) {
Chris@335 1706 Clipboard::Point point(i->frame, i->value, i->duration, i->level, i->label);
Chris@360 1707 point.setReferenceFrame(alignToReference(v, i->frame));
Chris@76 1708 to.addPoint(point);
Chris@76 1709 }
Chris@76 1710 }
Chris@76 1711 }
Chris@76 1712
Chris@125 1713 bool
Chris@805 1714 FlexiNoteLayer::paste(View *v, const Clipboard &from, int /*frameOffset */, bool /* interactive */)
Chris@76 1715 {
Chris@125 1716 if (!m_model) return false;
Chris@99 1717
Chris@76 1718 const Clipboard::PointList &points = from.getPoints();
Chris@76 1719
Chris@360 1720 bool realign = false;
Chris@360 1721
Chris@360 1722 if (clipboardHasDifferentAlignment(v, from)) {
Chris@360 1723
Chris@360 1724 QMessageBox::StandardButton button =
Chris@360 1725 QMessageBox::question(v, tr("Re-align pasted items?"),
Chris@360 1726 tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"),
Chris@360 1727 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
Chris@360 1728 QMessageBox::Yes);
Chris@360 1729
Chris@360 1730 if (button == QMessageBox::Cancel) {
Chris@360 1731 return false;
Chris@360 1732 }
Chris@360 1733
Chris@360 1734 if (button == QMessageBox::Yes) {
Chris@360 1735 realign = true;
Chris@360 1736 }
Chris@360 1737 }
Chris@360 1738
matthiasm@620 1739 FlexiNoteModel::EditCommand *command =
Chris@714 1740 new FlexiNoteModel::EditCommand(m_model, tr("Paste"));
Chris@76 1741
Chris@76 1742 for (Clipboard::PointList::const_iterator i = points.begin();
Chris@76 1743 i != points.end(); ++i) {
Chris@76 1744
Chris@76 1745 if (!i->haveFrame()) continue;
Chris@805 1746 int frame = 0;
Chris@360 1747
Chris@360 1748 if (!realign) {
Chris@360 1749
Chris@360 1750 frame = i->getFrame();
Chris@360 1751
Chris@360 1752 } else {
Chris@360 1753
Chris@360 1754 if (i->haveReferenceFrame()) {
Chris@360 1755 frame = i->getReferenceFrame();
Chris@360 1756 frame = alignFromReference(v, frame);
Chris@360 1757 } else {
Chris@360 1758 frame = i->getFrame();
Chris@360 1759 }
Chris@76 1760 }
Chris@360 1761
matthiasm@620 1762 FlexiNoteModel::Point newPoint(frame);
Chris@76 1763
Chris@76 1764 if (i->haveLabel()) newPoint.label = i->getLabel();
Chris@76 1765 if (i->haveValue()) newPoint.value = i->getValue();
Chris@76 1766 else newPoint.value = (m_model->getValueMinimum() +
Chris@76 1767 m_model->getValueMaximum()) / 2;
Chris@335 1768 if (i->haveLevel()) newPoint.level = i->getLevel();
Chris@76 1769 if (i->haveDuration()) newPoint.duration = i->getDuration();
Chris@125 1770 else {
Chris@805 1771 int nextFrame = frame;
Chris@125 1772 Clipboard::PointList::const_iterator j = i;
Chris@125 1773 for (; j != points.end(); ++j) {
Chris@125 1774 if (!j->haveFrame()) continue;
Chris@125 1775 if (j != i) break;
Chris@125 1776 }
Chris@125 1777 if (j != points.end()) {
Chris@125 1778 nextFrame = j->getFrame();
Chris@125 1779 }
Chris@125 1780 if (nextFrame == frame) {
Chris@125 1781 newPoint.duration = m_model->getResolution();
Chris@125 1782 } else {
Chris@125 1783 newPoint.duration = nextFrame - frame;
Chris@125 1784 }
Chris@125 1785 }
Chris@76 1786
Chris@76 1787 command->addPoint(newPoint);
Chris@76 1788 }
Chris@76 1789
Chris@376 1790 finish(command);
Chris@125 1791 return true;
Chris@76 1792 }
Chris@76 1793
Chris@507 1794 void
Chris@806 1795 FlexiNoteLayer::addNoteOn(int frame, int pitch, int velocity)
Chris@507 1796 {
matthiasm@620 1797 m_pendingNoteOns.insert(FlexiNote(frame, pitch, 0, float(velocity) / 127.0, ""));
Chris@507 1798 }
Chris@507 1799
Chris@507 1800 void
Chris@806 1801 FlexiNoteLayer::addNoteOff(int frame, int pitch)
Chris@507 1802 {
matthiasm@620 1803 for (FlexiNoteSet::iterator i = m_pendingNoteOns.begin();
Chris@507 1804 i != m_pendingNoteOns.end(); ++i) {
Chris@507 1805 if (lrintf((*i).value) == pitch) {
matthiasm@620 1806 FlexiNote note(*i);
Chris@507 1807 m_pendingNoteOns.erase(i);
Chris@507 1808 note.duration = frame - note.frame;
Chris@507 1809 if (m_model) {
matthiasm@620 1810 FlexiNoteModel::AddPointCommand *c = new FlexiNoteModel::AddPointCommand
matthiasm@620 1811 (m_model, note, tr("Record FlexiNote"));
Chris@507 1812 // execute and bundle:
Chris@507 1813 CommandHistory::getInstance()->addCommand(c, true, true);
Chris@507 1814 }
Chris@507 1815 break;
Chris@507 1816 }
Chris@507 1817 }
Chris@507 1818 }
Chris@507 1819
Chris@507 1820 void
matthiasm@620 1821 FlexiNoteLayer::abandonNoteOns()
Chris@507 1822 {
Chris@507 1823 m_pendingNoteOns.clear();
Chris@507 1824 }
Chris@507 1825
Chris@287 1826 int
matthiasm@620 1827 FlexiNoteLayer::getDefaultColourHint(bool darkbg, bool &impose)
Chris@287 1828 {
Chris@287 1829 impose = false;
Chris@287 1830 return ColourDatabase::getInstance()->getColourIndex
Chris@287 1831 (QString(darkbg ? "White" : "Black"));
Chris@287 1832 }
Chris@287 1833
Chris@316 1834 void
matthiasm@620 1835 FlexiNoteLayer::toXml(QTextStream &stream,
Chris@714 1836 QString indent, QString extraAttributes) const
Chris@30 1837 {
Chris@316 1838 SingleColourLayer::toXml(stream, indent, extraAttributes +
Chris@445 1839 QString(" verticalScale=\"%1\" scaleMinimum=\"%2\" scaleMaximum=\"%3\" ")
Chris@445 1840 .arg(m_verticalScale)
Chris@445 1841 .arg(m_scaleMinimum)
Chris@445 1842 .arg(m_scaleMaximum));
Chris@30 1843 }
Chris@30 1844
Chris@30 1845 void
matthiasm@620 1846 FlexiNoteLayer::setProperties(const QXmlAttributes &attributes)
Chris@30 1847 {
Chris@287 1848 SingleColourLayer::setProperties(attributes);
Chris@30 1849
Chris@805 1850 bool ok;
Chris@30 1851 VerticalScale scale = (VerticalScale)
Chris@714 1852 attributes.value("verticalScale").toInt(&ok);
Chris@30 1853 if (ok) setVerticalScale(scale);
Chris@445 1854
Chris@805 1855 // bool alsoOk;
Chris@805 1856 // float min = attributes.value("scaleMinimum").toFloat(&ok);
Chris@805 1857 // float max = attributes.value("scaleMaximum").toFloat(&alsoOk);
Chris@670 1858 // if (ok && alsoOk && min != max) setDisplayExtents(min, max);
Chris@30 1859 }
Chris@30 1860
matthiasm@651 1861 void
matthiasm@656 1862 FlexiNoteLayer::setVerticalRangeToNoteRange(View *v)
matthiasm@651 1863 {
matthiasm@656 1864 float minf = std::numeric_limits<float>::max();
matthiasm@651 1865 float maxf = 0;
matthiasm@656 1866 bool hasNotes = 0;
matthiasm@651 1867 for (FlexiNoteModel::PointList::const_iterator i = m_model->getPoints().begin();
matthiasm@651 1868 i != m_model->getPoints().end(); ++i) {
Chris@714 1869 hasNotes = 1;
Chris@714 1870 FlexiNote note = *i;
Chris@714 1871 if (note.value < minf) minf = note.value;
Chris@714 1872 if (note.value > maxf) maxf = note.value;
matthiasm@651 1873 }
matthiasm@651 1874
matthiasm@656 1875 std::cerr << "min frequency:" << minf << ", max frequency: " << maxf << std::endl;
matthiasm@656 1876
matthiasm@656 1877 if (hasNotes) {
matthiasm@659 1878 v->getLayer(1)->setDisplayExtents(minf*0.66,maxf*1.5);
matthiasm@656 1879 // MM: this is a hack because we rely on
matthiasm@656 1880 // * this layer being automatically aligned to layer 1
matthiasm@656 1881 // * layer one is a log frequency layer.
matthiasm@651 1882 }
matthiasm@651 1883 }
Chris@30 1884
matthiasm@651 1885