annotate layer/FlexiNoteLayer.cpp @ 738:d26545a2a02d tonioni

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