svgui  1.9
NoteLayer.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "NoteLayer.h"
17 
18 #include "data/model/Model.h"
19 #include "base/RealTime.h"
20 #include "base/Profiler.h"
21 #include "base/Pitch.h"
22 #include "base/LogRange.h"
23 #include "base/RangeMapper.h"
24 #include "ColourDatabase.h"
25 #include "view/View.h"
26 
27 #include "PianoScale.h"
28 #include "LinearNumericalScale.h"
29 #include "LogNumericalScale.h"
30 
31 #include "data/model/NoteModel.h"
32 
33 #include "widgets/ItemEditDialog.h"
34 #include "widgets/TextAbbrev.h"
35 
36 #include <QPainter>
37 #include <QPainterPath>
38 #include <QMouseEvent>
39 #include <QTextStream>
40 #include <QMessageBox>
41 
42 #include <iostream>
43 #include <cmath>
44 #include <utility>
45 
46 //#define DEBUG_NOTE_LAYER 1
47 
50  m_model(0),
51  m_editing(false),
52  m_dragPointX(0),
53  m_dragPointY(0),
54  m_dragStartX(0),
55  m_dragStartY(0),
56  m_originalPoint(0, 0.0, 0, 1.f, tr("New Point")),
57  m_editingPoint(0, 0.0, 0, 1.f, tr("New Point")),
58  m_editingCommand(0),
59  m_verticalScale(AutoAlignScale),
60  m_scaleMinimum(0),
61  m_scaleMaximum(0)
62 {
63  SVDEBUG << "constructed NoteLayer" << endl;
64 }
65 
66 void
67 NoteLayer::setModel(NoteModel *model)
68 {
69  if (m_model == model) return;
70  m_model = model;
71 
73 
74 // SVDEBUG << "NoteLayer::setModel(" << model << ")" << endl;
75 
76  m_scaleMinimum = 0;
77  m_scaleMaximum = 0;
78 
79  emit modelReplaced();
80 }
81 
82 Layer::PropertyList
84 {
85  PropertyList list = SingleColourLayer::getProperties();
86  list.push_back("Vertical Scale");
87  list.push_back("Scale Units");
88  return list;
89 }
90 
91 QString
92 NoteLayer::getPropertyLabel(const PropertyName &name) const
93 {
94  if (name == "Vertical Scale") return tr("Vertical Scale");
95  if (name == "Scale Units") return tr("Scale Units");
97 }
98 
99 Layer::PropertyType
100 NoteLayer::getPropertyType(const PropertyName &name) const
101 {
102  if (name == "Scale Units") return UnitsProperty;
103  if (name == "Vertical Scale") return ValueProperty;
105 }
106 
107 QString
108 NoteLayer::getPropertyGroupName(const PropertyName &name) const
109 {
110  if (name == "Vertical Scale" || name == "Scale Units") {
111  return tr("Scale");
112  }
114 }
115 
116 QString
118 {
119  if (m_model) return m_model->getScaleUnits();
120  else return "";
121 }
122 
123 int
124 NoteLayer::getPropertyRangeAndValue(const PropertyName &name,
125  int *min, int *max, int *deflt) const
126 {
127  int val = 0;
128 
129  if (name == "Vertical Scale") {
130 
131  if (min) *min = 0;
132  if (max) *max = 3;
133  if (deflt) *deflt = int(AutoAlignScale);
134 
135  val = int(m_verticalScale);
136 
137  } else if (name == "Scale Units") {
138 
139  if (deflt) *deflt = 0;
140  if (m_model) {
141  val = UnitDatabase::getInstance()->getUnitId
142  (getScaleUnits());
143  }
144 
145  } else {
146 
147  val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
148  }
149 
150  return val;
151 }
152 
153 QString
154 NoteLayer::getPropertyValueLabel(const PropertyName &name,
155  int value) const
156 {
157  if (name == "Vertical Scale") {
158  switch (value) {
159  default:
160  case 0: return tr("Auto-Align");
161  case 1: return tr("Linear");
162  case 2: return tr("Log");
163  case 3: return tr("MIDI Notes");
164  }
165  }
166  return SingleColourLayer::getPropertyValueLabel(name, value);
167 }
168 
169 void
170 NoteLayer::setProperty(const PropertyName &name, int value)
171 {
172  if (name == "Vertical Scale") {
174  } else if (name == "Scale Units") {
175  if (m_model) {
176  m_model->setScaleUnits
177  (UnitDatabase::getInstance()->getUnitById(value));
178  emit modelChanged();
179  }
180  } else {
181  return SingleColourLayer::setProperty(name, value);
182  }
183 }
184 
185 void
187 {
188  if (m_verticalScale == scale) return;
189  m_verticalScale = scale;
190  emit layerParametersChanged();
191 }
192 
193 bool
195 {
196  QPoint discard;
197  return !v->shouldIlluminateLocalFeatures(this, discard);
198 }
199 
200 bool
202 {
203  QString unit = getScaleUnits();
204  return (unit != "Hz");
205 // if (unit == "" ||
206 // unit.startsWith("MIDI") ||
207 // unit.startsWith("midi")) return true;
208 // return false;
209 }
210 
211 bool
212 NoteLayer::getValueExtents(float &min, float &max,
213  bool &logarithmic, QString &unit) const
214 {
215  if (!m_model) return false;
216  min = m_model->getValueMinimum();
217  max = m_model->getValueMaximum();
218 
219  if (shouldConvertMIDIToHz()) {
220  unit = "Hz";
221  min = Pitch::getFrequencyForPitch(lrintf(min));
222  max = Pitch::getFrequencyForPitch(lrintf(max + 1));
223  } else unit = getScaleUnits();
224 
226  m_verticalScale == LogScale) logarithmic = true;
227 
228  return true;
229 }
230 
231 bool
232 NoteLayer::getDisplayExtents(float &min, float &max) const
233 {
234  if (!m_model || shouldAutoAlign()) return false;
235 
237  min = Pitch::getFrequencyForPitch(0);
238  max = Pitch::getFrequencyForPitch(127);
239  return true;
240  }
241 
243  min = m_model->getValueMinimum();
244  max = m_model->getValueMaximum();
245  } else {
246  min = m_scaleMinimum;
247  max = m_scaleMaximum;
248  }
249 
250  if (shouldConvertMIDIToHz()) {
251  min = Pitch::getFrequencyForPitch(lrintf(min));
252  max = Pitch::getFrequencyForPitch(lrintf(max + 1));
253  }
254 
255 #ifdef DEBUG_NOTE_LAYER
256  cerr << "NoteLayer::getDisplayExtents: min = " << min << ", max = " << max << " (m_scaleMinimum = " << m_scaleMinimum << ", m_scaleMaximum = " << m_scaleMaximum << ")" << endl;
257 #endif
258 
259  return true;
260 }
261 
262 bool
263 NoteLayer::setDisplayExtents(float min, float max)
264 {
265  if (!m_model) return false;
266 
267  if (min == max) {
268  if (min == 0.f) {
269  max = 1.f;
270  } else {
271  max = min * 1.0001;
272  }
273  }
274 
275  m_scaleMinimum = min;
276  m_scaleMaximum = max;
277 
278 #ifdef DEBUG_NOTE_LAYER
279  cerr << "NoteLayer::setDisplayExtents: min = " << min << ", max = " << max << endl;
280 #endif
281 
282  emit layerParametersChanged();
283  return true;
284 }
285 
286 int
287 NoteLayer::getVerticalZoomSteps(int &defaultStep) const
288 {
289  if (shouldAutoAlign()) return 0;
290  if (!m_model) return 0;
291 
292  defaultStep = 0;
293  return 100;
294 }
295 
296 int
298 {
299  if (shouldAutoAlign()) return 0;
300  if (!m_model) return 0;
301 
302  RangeMapper *mapper = getNewVerticalZoomRangeMapper();
303  if (!mapper) return 0;
304 
305  float dmin, dmax;
306  getDisplayExtents(dmin, dmax);
307 
308  int nr = mapper->getPositionForValue(dmax - dmin);
309 
310  delete mapper;
311 
312  return 100 - nr;
313 }
314 
316 
317 void
319 {
320  if (shouldAutoAlign()) return;
321  if (!m_model) return;
322 
323  RangeMapper *mapper = getNewVerticalZoomRangeMapper();
324  if (!mapper) return;
325 
326  float min, max;
327  bool logarithmic;
328  QString unit;
329  getValueExtents(min, max, logarithmic, unit);
330 
331  float dmin, dmax;
332  getDisplayExtents(dmin, dmax);
333 
334  float newdist = mapper->getValueForPosition(100 - step);
335 
336  float newmin, newmax;
337 
338  if (logarithmic) {
339 
340  // see SpectrogramLayer::setVerticalZoomStep
341 
342  newmax = (newdist + sqrtf(newdist*newdist + 4*dmin*dmax)) / 2;
343  newmin = newmax - newdist;
344 
345 // cerr << "newmin = " << newmin << ", newmax = " << newmax << endl;
346 
347  } else {
348  float dmid = (dmax + dmin) / 2;
349  newmin = dmid - newdist / 2;
350  newmax = dmid + newdist / 2;
351  }
352 
353  if (newmin < min) {
354  newmax += (min - newmin);
355  newmin = min;
356  }
357  if (newmax > max) {
358  newmax = max;
359  }
360 
361 #ifdef DEBUG_NOTE_LAYER
362  cerr << "NoteLayer::setVerticalZoomStep: " << step << ": " << newmin << " -> " << newmax << " (range " << newdist << ")" << endl;
363 #endif
364 
365  setDisplayExtents(newmin, newmax);
366 }
367 
368 RangeMapper *
370 {
371  if (!m_model) return 0;
372 
373  RangeMapper *mapper;
374 
375  float min, max;
376  bool logarithmic;
377  QString unit;
378  getValueExtents(min, max, logarithmic, unit);
379 
380  if (min == max) return 0;
381 
382  if (logarithmic) {
383  mapper = new LogRangeMapper(0, 100, min, max, unit);
384  } else {
385  mapper = new LinearRangeMapper(0, 100, min, max, unit);
386  }
387 
388  return mapper;
389 }
390 
391 NoteModel::PointList
393 {
394  if (!m_model) return NoteModel::PointList();
395 
396  int frame = v->getFrameForX(x);
397 
398  NoteModel::PointList onPoints =
399  m_model->getPoints(frame);
400 
401  if (!onPoints.empty()) {
402  return onPoints;
403  }
404 
405  NoteModel::PointList prevPoints =
406  m_model->getPreviousPoints(frame);
407  NoteModel::PointList nextPoints =
408  m_model->getNextPoints(frame);
409 
410  NoteModel::PointList usePoints = prevPoints;
411 
412  if (prevPoints.empty()) {
413  usePoints = nextPoints;
414  } else if (int(prevPoints.begin()->frame) < v->getStartFrame() &&
415  !(nextPoints.begin()->frame > v->getEndFrame())) {
416  usePoints = nextPoints;
417  } else if (int(nextPoints.begin()->frame) - frame <
418  frame - int(prevPoints.begin()->frame)) {
419  usePoints = nextPoints;
420  }
421 
422  if (!usePoints.empty()) {
423  int fuzz = 2;
424  int px = v->getXForFrame(usePoints.begin()->frame);
425  if ((px > x && px - x > fuzz) ||
426  (px < x && x - px > fuzz + 1)) {
427  usePoints.clear();
428  }
429  }
430 
431  return usePoints;
432 }
433 
434 bool
435 NoteLayer::getPointToDrag(View *v, int x, int y, NoteModel::Point &p) const
436 {
437  if (!m_model) return false;
438 
439  int frame = v->getFrameForX(x);
440 
441  NoteModel::PointList onPoints = m_model->getPoints(frame);
442  if (onPoints.empty()) return false;
443 
444 // cerr << "frame " << frame << ": " << onPoints.size() << " candidate points" << endl;
445 
446  int nearestDistance = -1;
447 
448  for (NoteModel::PointList::const_iterator i = onPoints.begin();
449  i != onPoints.end(); ++i) {
450 
451  int distance = getYForValue(v, (*i).value) - y;
452  if (distance < 0) distance = -distance;
453  if (nearestDistance == -1 || distance < nearestDistance) {
454  nearestDistance = distance;
455  p = *i;
456  }
457  }
458 
459  return true;
460 }
461 
462 QString
464 {
465  int x = pos.x();
466 
467  if (!m_model || !m_model->getSampleRate()) return "";
468 
469  NoteModel::PointList points = getLocalPoints(v, x);
470 
471  if (points.empty()) {
472  if (!m_model->isReady()) {
473  return tr("In progress");
474  } else {
475  return tr("No local points");
476  }
477  }
478 
479  Note note(0);
480  NoteModel::PointList::iterator i;
481 
482  for (i = points.begin(); i != points.end(); ++i) {
483 
484  int y = getYForValue(v, i->value);
485  int h = 3;
486 
487  if (m_model->getValueQuantization() != 0.0) {
488  h = y - getYForValue(v, i->value + m_model->getValueQuantization());
489  if (h < 3) h = 3;
490  }
491 
492  if (pos.y() >= y - h && pos.y() <= y) {
493  note = *i;
494  break;
495  }
496  }
497 
498  if (i == points.end()) return tr("No local points");
499 
500  RealTime rt = RealTime::frame2RealTime(note.frame,
501  m_model->getSampleRate());
502  RealTime rd = RealTime::frame2RealTime(note.duration,
503  m_model->getSampleRate());
504 
505  QString pitchText;
506 
507  if (shouldConvertMIDIToHz()) {
508 
509  int mnote = lrintf(note.value);
510  int cents = lrintf((note.value - mnote) * 100);
511  float freq = Pitch::getFrequencyForPitch(mnote, cents);
512  pitchText = tr("%1 (%2, %3 Hz)")
513  .arg(Pitch::getPitchLabel(mnote, cents))
514  .arg(mnote)
515  .arg(freq);
516 
517  } else if (getScaleUnits() == "Hz") {
518 
519  pitchText = tr("%1 Hz (%2, %3)")
520  .arg(note.value)
521  .arg(Pitch::getPitchLabelForFrequency(note.value))
522  .arg(Pitch::getPitchForFrequency(note.value));
523 
524  } else {
525  pitchText = tr("%1 %2")
526  .arg(note.value).arg(getScaleUnits());
527  }
528 
529  QString text;
530 
531  if (note.label == "") {
532  text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nNo label"))
533  .arg(rt.toText(true).c_str())
534  .arg(pitchText)
535  .arg(rd.toText(true).c_str());
536  } else {
537  text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nLabel:\t%4"))
538  .arg(rt.toText(true).c_str())
539  .arg(pitchText)
540  .arg(rd.toText(true).c_str())
541  .arg(note.label);
542  }
543 
544  pos = QPoint(v->getXForFrame(note.frame),
545  getYForValue(v, note.value));
546  return text;
547 }
548 
549 bool
551  int &resolution,
552  SnapType snap) const
553 {
554  if (!m_model) {
555  return Layer::snapToFeatureFrame(v, frame, resolution, snap);
556  }
557 
558  resolution = m_model->getResolution();
559  NoteModel::PointList points;
560 
561  if (snap == SnapNeighbouring) {
562 
563  points = getLocalPoints(v, v->getXForFrame(frame));
564  if (points.empty()) return false;
565  frame = points.begin()->frame;
566  return true;
567  }
568 
569  points = m_model->getPoints(frame, frame);
570  int snapped = frame;
571  bool found = false;
572 
573  for (NoteModel::PointList::const_iterator i = points.begin();
574  i != points.end(); ++i) {
575 
576  if (snap == SnapRight) {
577 
578  if (i->frame > frame) {
579  snapped = i->frame;
580  found = true;
581  break;
582  }
583 
584  } else if (snap == SnapLeft) {
585 
586  if (i->frame <= frame) {
587  snapped = i->frame;
588  found = true; // don't break, as the next may be better
589  } else {
590  break;
591  }
592 
593  } else { // nearest
594 
595  NoteModel::PointList::const_iterator j = i;
596  ++j;
597 
598  if (j == points.end()) {
599 
600  snapped = i->frame;
601  found = true;
602  break;
603 
604  } else if (j->frame >= frame) {
605 
606  if (j->frame - frame < frame - i->frame) {
607  snapped = j->frame;
608  } else {
609  snapped = i->frame;
610  }
611  found = true;
612  break;
613  }
614  }
615  }
616 
617  frame = snapped;
618  return found;
619 }
620 
621 void
622 NoteLayer::getScaleExtents(View *v, float &min, float &max, bool &log) const
623 {
624  min = 0.0;
625  max = 0.0;
626  log = false;
627 
628  QString queryUnits;
629  if (shouldConvertMIDIToHz()) queryUnits = "Hz";
630  else queryUnits = getScaleUnits();
631 
632  if (shouldAutoAlign()) {
633 
634  if (!v->getValueExtents(queryUnits, min, max, log)) {
635 
636  min = m_model->getValueMinimum();
637  max = m_model->getValueMaximum();
638 
639  if (shouldConvertMIDIToHz()) {
640  min = Pitch::getFrequencyForPitch(lrintf(min));
641  max = Pitch::getFrequencyForPitch(lrintf(max + 1));
642  }
643 
644 #ifdef DEBUG_NOTE_LAYER
645  cerr << "NoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << endl;
646 #endif
647 
648  } else if (log) {
649 
650  LogRange::mapRange(min, max);
651 
652 #ifdef DEBUG_NOTE_LAYER
653  cerr << "NoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << endl;
654 #endif
655 
656  }
657 
658  } else {
659 
660  getDisplayExtents(min, max);
661 
663  min = Pitch::getFrequencyForPitch(0);
664  max = Pitch::getFrequencyForPitch(127);
665  } else if (shouldConvertMIDIToHz()) {
666  min = Pitch::getFrequencyForPitch(lrintf(min));
667  max = Pitch::getFrequencyForPitch(lrintf(max + 1));
668  }
669 
671  LogRange::mapRange(min, max);
672  log = true;
673  }
674  }
675 
676  if (max == min) max = min + 1.0;
677 }
678 
679 int
680 NoteLayer::getYForValue(View *v, float val) const
681 {
682  float min = 0.0, max = 0.0;
683  bool logarithmic = false;
684  int h = v->height();
685 
686  getScaleExtents(v, min, max, logarithmic);
687 
688 #ifdef DEBUG_NOTE_LAYER
689  cerr << "NoteLayer[" << this << "]::getYForValue(" << val << "): min = " << min << ", max = " << max << ", log = " << logarithmic << endl;
690 #endif
691 
692  if (shouldConvertMIDIToHz()) {
693  val = Pitch::getFrequencyForPitch(lrintf(val),
694  lrintf((val - lrintf(val)) * 100));
695 #ifdef DEBUG_NOTE_LAYER
696  cerr << "shouldConvertMIDIToHz true, val now = " << val << endl;
697 #endif
698  }
699 
700  if (logarithmic) {
701  val = LogRange::map(val);
702 #ifdef DEBUG_NOTE_LAYER
703  cerr << "logarithmic true, val now = " << val << endl;
704 #endif
705  }
706 
707  int y = int(h - ((val - min) * h) / (max - min)) - 1;
708 #ifdef DEBUG_NOTE_LAYER
709  cerr << "y = " << y << endl;
710 #endif
711  return y;
712 }
713 
714 float
716 {
717  float min = 0.0, max = 0.0;
718  bool logarithmic = false;
719  int h = v->height();
720 
721  getScaleExtents(v, min, max, logarithmic);
722 
723  float val = min + (float(h - y) * float(max - min)) / h;
724 
725  if (logarithmic) {
726  val = powf(10.f, val);
727  }
728 
729  if (shouldConvertMIDIToHz()) {
730  val = Pitch::getPitchForFrequency(val);
731  }
732 
733  return val;
734 }
735 
736 bool
738 {
739  if (!m_model) return false;
740  return (m_verticalScale == AutoAlignScale);
741 }
742 
743 void
744 NoteLayer::paint(View *v, QPainter &paint, QRect rect) const
745 {
746  if (!m_model || !m_model->isOK()) return;
747 
748  int sampleRate = m_model->getSampleRate();
749  if (!sampleRate) return;
750 
751 // Profiler profiler("NoteLayer::paint", true);
752 
753  int x0 = rect.left(), x1 = rect.right();
754  int frame0 = v->getFrameForX(x0);
755  int frame1 = v->getFrameForX(x1);
756 
757  NoteModel::PointList points(m_model->getPoints(frame0, frame1));
758  if (points.empty()) return;
759 
760  paint.setPen(getBaseQColor());
761 
762  QColor brushColour(getBaseQColor());
763  brushColour.setAlpha(80);
764 
765 // SVDEBUG << "NoteLayer::paint: resolution is "
766 // << m_model->getResolution() << " frames" << endl;
767 
768  float min = m_model->getValueMinimum();
769  float max = m_model->getValueMaximum();
770  if (max == min) max = min + 1.0;
771 
772  QPoint localPos;
773  NoteModel::Point illuminatePoint(0);
774  bool shouldIlluminate = false;
775 
776  if (v->shouldIlluminateLocalFeatures(this, localPos)) {
777  shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(),
778  illuminatePoint);
779  }
780 
781  paint.save();
782  paint.setRenderHint(QPainter::Antialiasing, false);
783 
784  for (NoteModel::PointList::const_iterator i = points.begin();
785  i != points.end(); ++i) {
786 
787  const NoteModel::Point &p(*i);
788 
789  int x = v->getXForFrame(p.frame);
790  int y = getYForValue(v, p.value);
791  int w = v->getXForFrame(p.frame + p.duration) - x;
792  int h = 3;
793 
794  if (m_model->getValueQuantization() != 0.0) {
795  h = y - getYForValue(v, p.value + m_model->getValueQuantization());
796  if (h < 3) h = 3;
797  }
798 
799  if (w < 1) w = 1;
800  paint.setPen(getBaseQColor());
801  paint.setBrush(brushColour);
802 
803  if (shouldIlluminate &&
804  // "illuminatePoint == p"
805  !NoteModel::Point::Comparator()(illuminatePoint, p) &&
806  !NoteModel::Point::Comparator()(p, illuminatePoint)) {
807 
808  paint.setPen(v->getForeground());
809  paint.setBrush(v->getForeground());
810 
811  QString vlabel = QString("%1%2").arg(p.value).arg(getScaleUnits());
813  x - paint.fontMetrics().width(vlabel) - 2,
814  y + paint.fontMetrics().height()/2
815  - paint.fontMetrics().descent(),
816  vlabel, View::OutlinedText);
817 
818  QString hlabel = RealTime::frame2RealTime
819  (p.frame, m_model->getSampleRate()).toText(true).c_str();
821  x,
822  y - h/2 - paint.fontMetrics().descent() - 2,
823  hlabel, View::OutlinedText);
824  }
825 
826  paint.drawRect(x, y - h/2, w, h);
827  }
828 
829  paint.restore();
830 }
831 
832 int
833 NoteLayer::getVerticalScaleWidth(View *v, bool, QPainter &paint) const
834 {
835  if (!m_model || shouldAutoAlign()) {
836  return 0;
837  } else {
839  return LogNumericalScale().getWidth(v, paint) + 10; // for piano
840  } else {
841  return LinearNumericalScale().getWidth(v, paint);
842  }
843  }
844 }
845 
846 void
847 NoteLayer::paintVerticalScale(View *v, bool, QPainter &paint, QRect) const
848 {
849  if (!m_model || m_model->getPoints().empty()) return;
850 
851  QString unit;
852  float min, max;
853  bool logarithmic;
854 
855  int w = getVerticalScaleWidth(v, false, paint);
856  int h = v->height();
857 
858  getScaleExtents(v, min, max, logarithmic);
859 
860  if (logarithmic) {
861  LogNumericalScale().paintVertical(v, this, paint, 0, min, max);
862  } else {
863  LinearNumericalScale().paintVertical(v, this, paint, 0, min, max);
864  }
865 
866  if (logarithmic && (getScaleUnits() == "Hz")) {
868  (v, paint, QRect(w - 10, 0, 10, h),
869  LogRange::unmap(min),
870  LogRange::unmap(max));
871  paint.drawLine(w, 0, w, h);
872  }
873 
874  if (getScaleUnits() != "") {
875  int mw = w - 5;
876  paint.drawText(5,
877  5 + paint.fontMetrics().ascent(),
879  paint.fontMetrics(),
880  mw));
881  }
882 }
883 
884 void
885 NoteLayer::drawStart(View *v, QMouseEvent *e)
886 {
887 // SVDEBUG << "NoteLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl;
888 
889  if (!m_model) return;
890 
891  int frame = v->getFrameForX(e->x());
892  if (frame < 0) frame = 0;
893  frame = frame / m_model->getResolution() * m_model->getResolution();
894 
895  float value = getValueForY(v, e->y());
896 
897  m_editingPoint = NoteModel::Point(frame, value, 0, 0.8, tr("New Point"));
899 
901  m_editingCommand = new NoteModel::EditCommand(m_model,
902  tr("Draw Point"));
903  m_editingCommand->addPoint(m_editingPoint);
904 
905  m_editing = true;
906 }
907 
908 void
909 NoteLayer::drawDrag(View *v, QMouseEvent *e)
910 {
911 // SVDEBUG << "NoteLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl;
912 
913  if (!m_model || !m_editing) return;
914 
915  int frame = v->getFrameForX(e->x());
916  if (frame < 0) frame = 0;
917  frame = frame / m_model->getResolution() * m_model->getResolution();
918 
919  float newValue = getValueForY(v, e->y());
920 
921  int newFrame = m_editingPoint.frame;
922  int newDuration = frame - newFrame;
923  if (newDuration < 0) {
924  newFrame = frame;
925  newDuration = -newDuration;
926  } else if (newDuration == 0) {
927  newDuration = 1;
928  }
929 
930  m_editingCommand->deletePoint(m_editingPoint);
931  m_editingPoint.frame = newFrame;
932  m_editingPoint.value = newValue;
933  m_editingPoint.duration = newDuration;
934  m_editingCommand->addPoint(m_editingPoint);
935 }
936 
937 void
938 NoteLayer::drawEnd(View *, QMouseEvent *)
939 {
940 // SVDEBUG << "NoteLayer::drawEnd(" << e->x() << "," << e->y() << ")" << endl;
941  if (!m_model || !m_editing) return;
943  m_editingCommand = 0;
944  m_editing = false;
945 }
946 
947 void
948 NoteLayer::eraseStart(View *v, QMouseEvent *e)
949 {
950  if (!m_model) return;
951 
952  if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return;
953 
954  if (m_editingCommand) {
956  m_editingCommand = 0;
957  }
958 
959  m_editing = true;
960 }
961 
962 void
963 NoteLayer::eraseDrag(View *, QMouseEvent *)
964 {
965 }
966 
967 void
968 NoteLayer::eraseEnd(View *v, QMouseEvent *e)
969 {
970  if (!m_model || !m_editing) return;
971 
972  m_editing = false;
973 
974  NoteModel::Point p(0);
975  if (!getPointToDrag(v, e->x(), e->y(), p)) return;
976  if (p.frame != m_editingPoint.frame || p.value != m_editingPoint.value) return;
977 
978  m_editingCommand = new NoteModel::EditCommand(m_model, tr("Erase Point"));
979 
980  m_editingCommand->deletePoint(m_editingPoint);
981 
983  m_editingCommand = 0;
984  m_editing = false;
985 }
986 
987 void
988 NoteLayer::editStart(View *v, QMouseEvent *e)
989 {
990 // SVDEBUG << "NoteLayer::editStart(" << e->x() << "," << e->y() << ")" << endl;
991 
992  if (!m_model) return;
993 
994  if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return;
996 
999 
1000  if (m_editingCommand) {
1002  m_editingCommand = 0;
1003  }
1004 
1005  m_editing = true;
1006  m_dragStartX = e->x();
1007  m_dragStartY = e->y();
1008 }
1009 
1010 void
1011 NoteLayer::editDrag(View *v, QMouseEvent *e)
1012 {
1013 // SVDEBUG << "NoteLayer::editDrag(" << e->x() << "," << e->y() << ")" << endl;
1014 
1015  if (!m_model || !m_editing) return;
1016 
1017  int xdist = e->x() - m_dragStartX;
1018  int ydist = e->y() - m_dragStartY;
1019  int newx = m_dragPointX + xdist;
1020  int newy = m_dragPointY + ydist;
1021 
1022  int frame = v->getFrameForX(newx);
1023  if (frame < 0) frame = 0;
1024  frame = frame / m_model->getResolution() * m_model->getResolution();
1025 
1026  float value = getValueForY(v, newy);
1027 
1028  if (!m_editingCommand) {
1029  m_editingCommand = new NoteModel::EditCommand(m_model,
1030  tr("Drag Point"));
1031  }
1032 
1033  m_editingCommand->deletePoint(m_editingPoint);
1034  m_editingPoint.frame = frame;
1035  m_editingPoint.value = value;
1036  m_editingCommand->addPoint(m_editingPoint);
1037 }
1038 
1039 void
1040 NoteLayer::editEnd(View *, QMouseEvent *)
1041 {
1042 // SVDEBUG << "NoteLayer::editEnd(" << e->x() << "," << e->y() << ")" << endl;
1043  if (!m_model || !m_editing) return;
1044 
1045  if (m_editingCommand) {
1046 
1047  QString newName = m_editingCommand->getName();
1048 
1049  if (m_editingPoint.frame != m_originalPoint.frame) {
1050  if (m_editingPoint.value != m_originalPoint.value) {
1051  newName = tr("Edit Point");
1052  } else {
1053  newName = tr("Relocate Point");
1054  }
1055  } else {
1056  newName = tr("Change Point Value");
1057  }
1058 
1059  m_editingCommand->setName(newName);
1061  }
1062 
1063  m_editingCommand = 0;
1064  m_editing = false;
1065 }
1066 
1067 bool
1068 NoteLayer::editOpen(View *v, QMouseEvent *e)
1069 {
1070  if (!m_model) return false;
1071 
1072  NoteModel::Point note(0);
1073  if (!getPointToDrag(v, e->x(), e->y(), note)) return false;
1074 
1075 // NoteModel::Point note = *points.begin();
1076 
1077  ItemEditDialog *dialog = new ItemEditDialog
1078  (m_model->getSampleRate(),
1083  getScaleUnits());
1084 
1085  dialog->setFrameTime(note.frame);
1086  dialog->setValue(note.value);
1087  dialog->setFrameDuration(note.duration);
1088  dialog->setText(note.label);
1089 
1090  if (dialog->exec() == QDialog::Accepted) {
1091 
1092  NoteModel::Point newNote = note;
1093  newNote.frame = dialog->getFrameTime();
1094  newNote.value = dialog->getValue();
1095  newNote.duration = dialog->getFrameDuration();
1096  newNote.label = dialog->getText();
1097 
1098  NoteModel::EditCommand *command = new NoteModel::EditCommand
1099  (m_model, tr("Edit Point"));
1100  command->deletePoint(note);
1101  command->addPoint(newNote);
1102  finish(command);
1103  }
1104 
1105  delete dialog;
1106  return true;
1107 }
1108 
1109 void
1110 NoteLayer::moveSelection(Selection s, int newStartFrame)
1111 {
1112  if (!m_model) return;
1113 
1114  NoteModel::EditCommand *command =
1115  new NoteModel::EditCommand(m_model, tr("Drag Selection"));
1116 
1117  NoteModel::PointList points =
1118  m_model->getPoints(s.getStartFrame(), s.getEndFrame());
1119 
1120  for (NoteModel::PointList::iterator i = points.begin();
1121  i != points.end(); ++i) {
1122 
1123  if (s.contains(i->frame)) {
1124  NoteModel::Point newPoint(*i);
1125  newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
1126  command->deletePoint(*i);
1127  command->addPoint(newPoint);
1128  }
1129  }
1130 
1131  finish(command);
1132 }
1133 
1134 void
1135 NoteLayer::resizeSelection(Selection s, Selection newSize)
1136 {
1137  if (!m_model) return;
1138 
1139  NoteModel::EditCommand *command =
1140  new NoteModel::EditCommand(m_model, tr("Resize Selection"));
1141 
1142  NoteModel::PointList points =
1143  m_model->getPoints(s.getStartFrame(), s.getEndFrame());
1144 
1145  double ratio =
1146  double(newSize.getEndFrame() - newSize.getStartFrame()) /
1147  double(s.getEndFrame() - s.getStartFrame());
1148 
1149  for (NoteModel::PointList::iterator i = points.begin();
1150  i != points.end(); ++i) {
1151 
1152  if (s.contains(i->frame)) {
1153 
1154  double targetStart = i->frame;
1155  targetStart = newSize.getStartFrame() +
1156  double(targetStart - s.getStartFrame()) * ratio;
1157 
1158  double targetEnd = i->frame + i->duration;
1159  targetEnd = newSize.getStartFrame() +
1160  double(targetEnd - s.getStartFrame()) * ratio;
1161 
1162  NoteModel::Point newPoint(*i);
1163  newPoint.frame = lrint(targetStart);
1164  newPoint.duration = lrint(targetEnd - targetStart);
1165  command->deletePoint(*i);
1166  command->addPoint(newPoint);
1167  }
1168  }
1169 
1170  finish(command);
1171 }
1172 
1173 void
1175 {
1176  if (!m_model) return;
1177 
1178  NoteModel::EditCommand *command =
1179  new NoteModel::EditCommand(m_model, tr("Delete Selected Points"));
1180 
1181  NoteModel::PointList points =
1182  m_model->getPoints(s.getStartFrame(), s.getEndFrame());
1183 
1184  for (NoteModel::PointList::iterator i = points.begin();
1185  i != points.end(); ++i) {
1186 
1187  if (s.contains(i->frame)) {
1188  command->deletePoint(*i);
1189  }
1190  }
1191 
1192  finish(command);
1193 }
1194 
1195 void
1196 NoteLayer::copy(View *v, Selection s, Clipboard &to)
1197 {
1198  if (!m_model) return;
1199 
1200  NoteModel::PointList points =
1201  m_model->getPoints(s.getStartFrame(), s.getEndFrame());
1202 
1203  for (NoteModel::PointList::iterator i = points.begin();
1204  i != points.end(); ++i) {
1205  if (s.contains(i->frame)) {
1206  Clipboard::Point point(i->frame, i->value, i->duration, i->level, i->label);
1207  point.setReferenceFrame(alignToReference(v, i->frame));
1208  to.addPoint(point);
1209  }
1210  }
1211 }
1212 
1213 bool
1214 NoteLayer::paste(View *v, const Clipboard &from, int /* frameOffset */, bool /* interactive */)
1215 {
1216  if (!m_model) return false;
1217 
1218  const Clipboard::PointList &points = from.getPoints();
1219 
1220  bool realign = false;
1221 
1222  if (clipboardHasDifferentAlignment(v, from)) {
1223 
1224  QMessageBox::StandardButton button =
1225  QMessageBox::question(v, tr("Re-align pasted items?"),
1226  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?"),
1227  QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
1228  QMessageBox::Yes);
1229 
1230  if (button == QMessageBox::Cancel) {
1231  return false;
1232  }
1233 
1234  if (button == QMessageBox::Yes) {
1235  realign = true;
1236  }
1237  }
1238 
1239  NoteModel::EditCommand *command =
1240  new NoteModel::EditCommand(m_model, tr("Paste"));
1241 
1242  for (Clipboard::PointList::const_iterator i = points.begin();
1243  i != points.end(); ++i) {
1244 
1245  if (!i->haveFrame()) continue;
1246  int frame = 0;
1247 
1248  if (!realign) {
1249 
1250  frame = i->getFrame();
1251 
1252  } else {
1253 
1254  if (i->haveReferenceFrame()) {
1255  frame = i->getReferenceFrame();
1256  frame = alignFromReference(v, frame);
1257  } else {
1258  frame = i->getFrame();
1259  }
1260  }
1261 
1262  NoteModel::Point newPoint(frame);
1263 
1264  if (i->haveLabel()) newPoint.label = i->getLabel();
1265  if (i->haveValue()) newPoint.value = i->getValue();
1266  else newPoint.value = (m_model->getValueMinimum() +
1267  m_model->getValueMaximum()) / 2;
1268  if (i->haveLevel()) newPoint.level = i->getLevel();
1269  if (i->haveDuration()) newPoint.duration = i->getDuration();
1270  else {
1271  int nextFrame = frame;
1272  Clipboard::PointList::const_iterator j = i;
1273  for (; j != points.end(); ++j) {
1274  if (!j->haveFrame()) continue;
1275  if (j != i) break;
1276  }
1277  if (j != points.end()) {
1278  nextFrame = j->getFrame();
1279  }
1280  if (nextFrame == frame) {
1281  newPoint.duration = m_model->getResolution();
1282  } else {
1283  newPoint.duration = nextFrame - frame;
1284  }
1285  }
1286 
1287  command->addPoint(newPoint);
1288  }
1289 
1290  finish(command);
1291  return true;
1292 }
1293 
1294 void
1295 NoteLayer::addNoteOn(int frame, int pitch, int velocity)
1296 {
1297  m_pendingNoteOns.insert(Note(frame, pitch, 0, float(velocity) / 127.0, ""));
1298 }
1299 
1300 void
1301 NoteLayer::addNoteOff(int frame, int pitch)
1302 {
1303  for (NoteSet::iterator i = m_pendingNoteOns.begin();
1304  i != m_pendingNoteOns.end(); ++i) {
1305  if (lrintf((*i).value) == pitch) {
1306  Note note(*i);
1307  m_pendingNoteOns.erase(i);
1308  note.duration = frame - note.frame;
1309  if (m_model) {
1310  NoteModel::AddPointCommand *c = new NoteModel::AddPointCommand
1311  (m_model, note, tr("Record Note"));
1312  // execute and bundle:
1313  CommandHistory::getInstance()->addCommand(c, true, true);
1314  }
1315  break;
1316  }
1317  }
1318 }
1319 
1320 void
1322 {
1323  m_pendingNoteOns.clear();
1324 }
1325 
1326 int
1327 NoteLayer::getDefaultColourHint(bool darkbg, bool &impose)
1328 {
1329  impose = false;
1331  (QString(darkbg ? "White" : "Black"));
1332 }
1333 
1334 void
1335 NoteLayer::toXml(QTextStream &stream,
1336  QString indent, QString extraAttributes) const
1337 {
1338  SingleColourLayer::toXml(stream, indent, extraAttributes +
1339  QString(" verticalScale=\"%1\" scaleMinimum=\"%2\" scaleMaximum=\"%3\" ")
1340  .arg(m_verticalScale)
1341  .arg(m_scaleMinimum)
1342  .arg(m_scaleMaximum));
1343 }
1344 
1345 void
1346 NoteLayer::setProperties(const QXmlAttributes &attributes)
1347 {
1349 
1350  bool ok, alsoOk;
1351  VerticalScale scale = (VerticalScale)
1352  attributes.value("verticalScale").toInt(&ok);
1353  if (ok) setVerticalScale(scale);
1354 
1355  float min = attributes.value("scaleMinimum").toFloat(&ok);
1356  float max = attributes.value("scaleMaximum").toFloat(&alsoOk);
1357  if (ok && alsoOk && min != max) setDisplayExtents(min, max);
1358 }
1359 
1360 
void paintPianoVertical(View *v, QPainter &paint, QRect rect, float minf, float maxf)
Definition: PianoScale.cpp:27
virtual void editDrag(View *v, QMouseEvent *)
Definition: NoteLayer.cpp:1011
int getFrameForX(int x) const
Return the closest frame to the given pixel x-coordinate.
Definition: View.cpp:363
void finish(NoteModel::EditCommand *command)
Definition: NoteLayer.h:168
virtual void copy(View *v, Selection s, Clipboard &to)
Definition: NoteLayer.cpp:1196
void getScaleExtents(View *, float &min, float &max, bool &log) const
Definition: NoteLayer.cpp:622
void setFrameTime(int frame)
virtual QString getPropertyGroupName(const PropertyName &) const
Definition: NoteLayer.cpp:108
virtual void eraseDrag(View *v, QMouseEvent *)
Definition: NoteLayer.cpp:963
int m_dragPointX
Definition: NoteLayer.h:151
bool shouldAutoAlign() const
Definition: NoteLayer.cpp:737
virtual bool snapToFeatureFrame(View *, int &, int &resolution, SnapType) const
Adjust the given frame to snap to the nearest feature, if possible.
Definition: Layer.h:183
void connectSignals(const Model *)
Definition: Layer.cpp:49
virtual bool getValueExtents(float &min, float &max, bool &log, QString &unit) const
Return the minimum and maximum values for the y axis of the model in this layer, as well as whether t...
Definition: NoteLayer.cpp:212
virtual bool editOpen(View *v, QMouseEvent *)
Open an editor on the item under the mouse (e.g.
Definition: NoteLayer.cpp:1068
virtual QColor getForeground() const
Definition: View.cpp:513
virtual bool getValueExtents(QString unit, float &min, float &max, bool &log) const
Definition: View.cpp:185
void modelReplaced()
static QString abbreviate(QString text, int maxLength, Policy policy=ElideEnd, bool fuzzy=true, QString ellipsis="")
Abbreviate the given text to the given maximum length (including ellipsis), using the given abbreviat...
Definition: TextAbbrev.cpp:74
int m_dragPointY
Definition: NoteLayer.h:152
virtual void moveSelection(Selection s, int newStartFrame)
Definition: NoteLayer.cpp:1110
virtual void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const
Convert the layer's data (though not those of the model it refers to) into XML for file output.
NoteModel::Point m_editingPoint
Definition: NoteLayer.h:156
void addCommand(Command *command)
Add a command to the command history.
void addNoteOn(int frame, int pitch, int velocity)
Add a note-on.
Definition: NoteLayer.cpp:1295
virtual PropertyList getProperties() const
Definition: NoteLayer.cpp:83
bool getPointToDrag(View *v, int x, int y, NoteModel::Point &) const
Definition: NoteLayer.cpp:435
virtual void setProperty(const PropertyName &, int value)
Definition: NoteLayer.cpp:170
virtual void setVerticalZoomStep(int)
!! lots of duplication with TimeValueLayer
Definition: NoteLayer.cpp:318
NoteModel::EditCommand * m_editingCommand
Definition: NoteLayer.h:157
virtual bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const
Definition: View.h:260
int getFrameTime() const
NoteModel::Point m_originalPoint
Definition: NoteLayer.h:155
virtual void drawEnd(View *v, QMouseEvent *)
Definition: NoteLayer.cpp:938
void paintVertical(View *v, const VerticalScaleLayer *layer, QPainter &paint, int x0, float minlog, float maxlog)
virtual int getPropertyRangeAndValue(const PropertyName &, int *min, int *max, int *deflt) const
Definition: NoteLayer.cpp:124
VerticalScale m_verticalScale
Definition: NoteLayer.h:158
void addNoteOff(int frame, int pitch)
Add a note-off.
Definition: NoteLayer.cpp:1301
virtual RangeMapper * getNewVerticalZoomRangeMapper() const
Create and return a range mapper for vertical zoom step values.
Definition: NoteLayer.cpp:369
virtual void paintVerticalScale(View *v, bool, QPainter &paint, QRect rect) const
Definition: NoteLayer.cpp:847
virtual QColor getBaseQColor() const
virtual void deleteSelection(Selection s)
Definition: NoteLayer.cpp:1174
void setProperties(const QXmlAttributes &attributes)
Set the particular properties of a layer (those specific to the subclass) from a set of XML attribute...
Definition: NoteLayer.cpp:1346
virtual void resizeSelection(Selection s, Selection newSize)
Definition: NoteLayer.cpp:1135
void setText(QString text)
virtual bool getDisplayExtents(float &min, float &max) const
Return the minimum and maximum values within the displayed range for the y axis, if only a subset of ...
Definition: NoteLayer.cpp:232
NoteSet m_pendingNoteOns
Definition: NoteLayer.h:161
virtual QString getFeatureDescription(View *v, QPoint &) const
Definition: NoteLayer.cpp:463
int m_dragStartX
Definition: NoteLayer.h:153
virtual void editStart(View *v, QMouseEvent *)
Definition: NoteLayer.cpp:988
void setModel(NoteModel *model)
Definition: NoteLayer.cpp:67
int getColourIndex(QString name) const
virtual void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const
Convert the layer's data (though not those of the model it refers to) into XML for file output.
Definition: NoteLayer.cpp:1335
int getWidth(View *v, QPainter &paint)
virtual void editEnd(View *v, QMouseEvent *)
Definition: NoteLayer.cpp:1040
virtual int getCurrentVerticalZoomStep() const
Get the current vertical zoom step.
Definition: NoteLayer.cpp:297
float m_scaleMaximum
Definition: NoteLayer.h:164
virtual bool setDisplayExtents(float min, float max)
Set the displayed minimum and maximum values for the y axis to the given range, if supported.
Definition: NoteLayer.cpp:263
float m_scaleMinimum
Definition: NoteLayer.h:163
virtual QString getPropertyLabel(const PropertyName &) const
virtual PropertyType getPropertyType(const PropertyName &) const
Definition: NoteLayer.cpp:100
int getStartFrame() const
Retrieve the first visible sample frame on the widget.
Definition: View.cpp:302
void paintVertical(View *v, const VerticalScaleLayer *layer, QPainter &paint, int x0, float minf, float maxf)
void layerParametersChanged()
virtual QString getPropertyLabel(const PropertyName &) const
Definition: NoteLayer.cpp:92
virtual QString getPropertyGroupName(const PropertyName &) const
int getWidth(View *v, QPainter &paint)
virtual void setProperties(const QXmlAttributes &attributes)
Set the particular properties of a layer (those specific to the subclass) from a set of XML attribute...
virtual void eraseStart(View *v, QMouseEvent *)
Definition: NoteLayer.cpp:948
int getEndFrame() const
Retrieve the last visible sample frame on the widget.
Definition: View.cpp:308
SnapType
Definition: Layer.h:157
virtual int getPropertyRangeAndValue(const PropertyName &, int *min, int *max, int *deflt) const
virtual QString getPropertyValueLabel(const PropertyName &, int value) const
Definition: NoteLayer.cpp:154
static CommandHistory * getInstance()
void abandonNoteOns()
Abandon all pending note-on events.
Definition: NoteLayer.cpp:1321
bool clipboardHasDifferentAlignment(View *v, const Clipboard &clip) const
Definition: Layer.cpp:193
virtual bool snapToFeatureFrame(View *v, int &frame, int &resolution, SnapType snap) const
Adjust the given frame to snap to the nearest feature, if possible.
Definition: NoteLayer.cpp:550
virtual bool isLayerScrollable(const View *v) const
This should return true if the layer can safely be scrolled automatically by a given view (simply cop...
Definition: NoteLayer.cpp:194
virtual void drawStart(View *v, QMouseEvent *)
Definition: NoteLayer.cpp:885
virtual void drawDrag(View *v, QMouseEvent *)
Definition: NoteLayer.cpp:909
void modelChanged()
virtual int alignFromReference(View *v, int frame) const
Definition: Layer.cpp:181
virtual int alignToReference(View *v, int frame) const
Definition: Layer.cpp:169
View is the base class of widgets that display one or more overlaid views of data against a horizonta...
Definition: View.h:50
float getValue() const
virtual QString getScaleUnits() const
Definition: NoteLayer.cpp:117
virtual int getVerticalScaleWidth(View *v, bool, QPainter &) const
Definition: NoteLayer.cpp:833
int m_dragStartY
Definition: NoteLayer.h:154
NoteModel::PointList getLocalPoints(View *v, int) const
Definition: NoteLayer.cpp:392
virtual float getValueForY(View *v, int y) const
Definition: NoteLayer.cpp:715
virtual QString getPropertyValueLabel(const PropertyName &, int value) const
virtual void drawVisibleText(QPainter &p, int x, int y, QString text, TextStyle style) const
Definition: View.cpp:787
bool m_editing
Definition: NoteLayer.h:150
bool shouldConvertMIDIToHz() const
Definition: NoteLayer.cpp:201
int getFrameDuration() const
void setVerticalScale(VerticalScale scale)
Definition: NoteLayer.cpp:186
virtual PropertyList getProperties() const
virtual int getDefaultColourHint(bool dark, bool &impose)
Definition: NoteLayer.cpp:1327
NoteModel * m_model
Definition: NoteLayer.h:149
virtual int getVerticalZoomSteps(int &defaultStep) const
Get the number of vertical zoom steps available for this layer.
Definition: NoteLayer.cpp:287
virtual void paint(View *v, QPainter &paint, QRect rect) const
Paint the given rectangle of this layer onto the given view using the given painter,...
Definition: NoteLayer.cpp:744
virtual PropertyType getPropertyType(const PropertyName &) const
int getXForFrame(int frame) const
Return the pixel x-coordinate corresponding to a given sample frame (which may be negative).
Definition: View.cpp:357
virtual bool paste(View *v, const Clipboard &from, int frameOffset, bool interactive)
Paste from the given clipboard onto the layer at the given frame offset.
Definition: NoteLayer.cpp:1214
static ColourDatabase * getInstance()
virtual void setProperty(const PropertyName &, int value)
virtual void eraseEnd(View *v, QMouseEvent *)
Definition: NoteLayer.cpp:968
void setValue(float value)
void setFrameDuration(int frame)
virtual int getYForValue(View *v, float value) const
VerticalScaleLayer methods.
Definition: NoteLayer.cpp:680
QString getText() const