annotate layer/NoteLayer.cpp @ 0:fc9323a41f5a

start base : Sonic Visualiser sv1-1.0rc1
author lbajardsilogic
date Fri, 11 May 2007 09:08:14 +0000
parents
children d8e6709e9075
rev   line source
lbajardsilogic@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
lbajardsilogic@0 2
lbajardsilogic@0 3 /*
lbajardsilogic@0 4 Sonic Visualiser
lbajardsilogic@0 5 An audio file viewer and annotation editor.
lbajardsilogic@0 6 Centre for Digital Music, Queen Mary, University of London.
lbajardsilogic@0 7 This file copyright 2006 Chris Cannam.
lbajardsilogic@0 8
lbajardsilogic@0 9 This program is free software; you can redistribute it and/or
lbajardsilogic@0 10 modify it under the terms of the GNU General Public License as
lbajardsilogic@0 11 published by the Free Software Foundation; either version 2 of the
lbajardsilogic@0 12 License, or (at your option) any later version. See the file
lbajardsilogic@0 13 COPYING included with this distribution for more information.
lbajardsilogic@0 14 */
lbajardsilogic@0 15
lbajardsilogic@0 16 #include "NoteLayer.h"
lbajardsilogic@0 17
lbajardsilogic@0 18 #include "data/model/Model.h"
lbajardsilogic@0 19 #include "base/RealTime.h"
lbajardsilogic@0 20 #include "base/Profiler.h"
lbajardsilogic@0 21 #include "base/Pitch.h"
lbajardsilogic@0 22 #include "base/LogRange.h"
lbajardsilogic@0 23 #include "view/View.h"
lbajardsilogic@0 24
lbajardsilogic@0 25 #include "data/model/NoteModel.h"
lbajardsilogic@0 26
lbajardsilogic@0 27 #include "widgets/ItemEditDialog.h"
lbajardsilogic@0 28
lbajardsilogic@0 29 #include "SpectrogramLayer.h" // for optional frequency alignment
lbajardsilogic@0 30
lbajardsilogic@0 31 #include <QPainter>
lbajardsilogic@0 32 #include <QPainterPath>
lbajardsilogic@0 33 #include <QMouseEvent>
lbajardsilogic@0 34
lbajardsilogic@0 35 #include <iostream>
lbajardsilogic@0 36 #include <cmath>
lbajardsilogic@0 37
lbajardsilogic@0 38 NoteLayer::NoteLayer() :
lbajardsilogic@0 39 Layer(),
lbajardsilogic@0 40 m_model(0),
lbajardsilogic@0 41 m_editing(false),
lbajardsilogic@0 42 m_originalPoint(0, 0.0, 0, tr("New Point")),
lbajardsilogic@0 43 m_editingPoint(0, 0.0, 0, tr("New Point")),
lbajardsilogic@0 44 m_editingCommand(0),
lbajardsilogic@0 45 m_colour(Qt::black),
lbajardsilogic@0 46 m_verticalScale(AutoAlignScale)
lbajardsilogic@0 47 {
lbajardsilogic@0 48
lbajardsilogic@0 49 }
lbajardsilogic@0 50
lbajardsilogic@0 51 void
lbajardsilogic@0 52 NoteLayer::setModel(NoteModel *model)
lbajardsilogic@0 53 {
lbajardsilogic@0 54 if (m_model == model) return;
lbajardsilogic@0 55 m_model = model;
lbajardsilogic@0 56
lbajardsilogic@0 57 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
lbajardsilogic@0 58 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
lbajardsilogic@0 59 this, SIGNAL(modelChanged(size_t, size_t)));
lbajardsilogic@0 60
lbajardsilogic@0 61 connect(m_model, SIGNAL(completionChanged()),
lbajardsilogic@0 62 this, SIGNAL(modelCompletionChanged()));
lbajardsilogic@0 63
lbajardsilogic@0 64 // std::cerr << "NoteLayer::setModel(" << model << ")" << std::endl;
lbajardsilogic@0 65
lbajardsilogic@0 66 emit modelReplaced();
lbajardsilogic@0 67 }
lbajardsilogic@0 68
lbajardsilogic@0 69 Layer::PropertyList
lbajardsilogic@0 70 NoteLayer::getProperties() const
lbajardsilogic@0 71 {
lbajardsilogic@0 72 PropertyList list;
lbajardsilogic@0 73 list.push_back("Colour");
lbajardsilogic@0 74 list.push_back("Vertical Scale");
lbajardsilogic@0 75 list.push_back("Scale Units");
lbajardsilogic@0 76 return list;
lbajardsilogic@0 77 }
lbajardsilogic@0 78
lbajardsilogic@0 79 QString
lbajardsilogic@0 80 NoteLayer::getPropertyLabel(const PropertyName &name) const
lbajardsilogic@0 81 {
lbajardsilogic@0 82 if (name == "Colour") return tr("Colour");
lbajardsilogic@0 83 if (name == "Vertical Scale") return tr("Vertical Scale");
lbajardsilogic@0 84 if (name == "Scale Units") return tr("Scale Units");
lbajardsilogic@0 85 return "";
lbajardsilogic@0 86 }
lbajardsilogic@0 87
lbajardsilogic@0 88 Layer::PropertyType
lbajardsilogic@0 89 NoteLayer::getPropertyType(const PropertyName &name) const
lbajardsilogic@0 90 {
lbajardsilogic@0 91 if (name == "Scale Units") return UnitsProperty;
lbajardsilogic@0 92 return ValueProperty;
lbajardsilogic@0 93 }
lbajardsilogic@0 94
lbajardsilogic@0 95 QString
lbajardsilogic@0 96 NoteLayer::getPropertyGroupName(const PropertyName &name) const
lbajardsilogic@0 97 {
lbajardsilogic@0 98 if (name == "Vertical Scale" || name == "Scale Units") {
lbajardsilogic@0 99 return tr("Scale");
lbajardsilogic@0 100 }
lbajardsilogic@0 101 return QString();
lbajardsilogic@0 102 }
lbajardsilogic@0 103
lbajardsilogic@0 104 int
lbajardsilogic@0 105 NoteLayer::getPropertyRangeAndValue(const PropertyName &name,
lbajardsilogic@0 106 int *min, int *max, int *deflt) const
lbajardsilogic@0 107 {
lbajardsilogic@0 108 //!!! factor this colour handling stuff out into a colour manager class
lbajardsilogic@0 109
lbajardsilogic@0 110 int val = 0;
lbajardsilogic@0 111
lbajardsilogic@0 112 if (name == "Colour") {
lbajardsilogic@0 113
lbajardsilogic@0 114 if (min) *min = 0;
lbajardsilogic@0 115 if (max) *max = 5;
lbajardsilogic@0 116 if (deflt) *deflt = 0;
lbajardsilogic@0 117
lbajardsilogic@0 118 if (m_colour == Qt::black) val = 0;
lbajardsilogic@0 119 else if (m_colour == Qt::darkRed) val = 1;
lbajardsilogic@0 120 else if (m_colour == Qt::darkBlue) val = 2;
lbajardsilogic@0 121 else if (m_colour == Qt::darkGreen) val = 3;
lbajardsilogic@0 122 else if (m_colour == QColor(200, 50, 255)) val = 4;
lbajardsilogic@0 123 else if (m_colour == QColor(255, 150, 50)) val = 5;
lbajardsilogic@0 124
lbajardsilogic@0 125 } else if (name == "Vertical Scale") {
lbajardsilogic@0 126
lbajardsilogic@0 127 if (min) *min = 0;
lbajardsilogic@0 128 if (max) *max = 3;
lbajardsilogic@0 129 if (deflt) *deflt = int(AutoAlignScale);
lbajardsilogic@0 130
lbajardsilogic@0 131 val = int(m_verticalScale);
lbajardsilogic@0 132
lbajardsilogic@0 133 } else if (name == "Scale Units") {
lbajardsilogic@0 134
lbajardsilogic@0 135 if (deflt) *deflt = 0;
lbajardsilogic@0 136 if (m_model) {
lbajardsilogic@0 137 val = UnitDatabase::getInstance()->getUnitId
lbajardsilogic@0 138 (m_model->getScaleUnits());
lbajardsilogic@0 139 }
lbajardsilogic@0 140
lbajardsilogic@0 141 } else {
lbajardsilogic@0 142
lbajardsilogic@0 143 val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
lbajardsilogic@0 144 }
lbajardsilogic@0 145
lbajardsilogic@0 146 return val;
lbajardsilogic@0 147 }
lbajardsilogic@0 148
lbajardsilogic@0 149 QString
lbajardsilogic@0 150 NoteLayer::getPropertyValueLabel(const PropertyName &name,
lbajardsilogic@0 151 int value) const
lbajardsilogic@0 152 {
lbajardsilogic@0 153 if (name == "Colour") {
lbajardsilogic@0 154 switch (value) {
lbajardsilogic@0 155 default:
lbajardsilogic@0 156 case 0: return tr("Black");
lbajardsilogic@0 157 case 1: return tr("Red");
lbajardsilogic@0 158 case 2: return tr("Blue");
lbajardsilogic@0 159 case 3: return tr("Green");
lbajardsilogic@0 160 case 4: return tr("Purple");
lbajardsilogic@0 161 case 5: return tr("Orange");
lbajardsilogic@0 162 }
lbajardsilogic@0 163 } else if (name == "Vertical Scale") {
lbajardsilogic@0 164 switch (value) {
lbajardsilogic@0 165 default:
lbajardsilogic@0 166 case 0: return tr("Auto-Align");
lbajardsilogic@0 167 case 1: return tr("Linear");
lbajardsilogic@0 168 case 2: return tr("Log");
lbajardsilogic@0 169 case 3: return tr("MIDI Notes");
lbajardsilogic@0 170 }
lbajardsilogic@0 171 }
lbajardsilogic@0 172 return tr("<unknown>");
lbajardsilogic@0 173 }
lbajardsilogic@0 174
lbajardsilogic@0 175 void
lbajardsilogic@0 176 NoteLayer::setProperty(const PropertyName &name, int value)
lbajardsilogic@0 177 {
lbajardsilogic@0 178 if (name == "Colour") {
lbajardsilogic@0 179 switch (value) {
lbajardsilogic@0 180 default:
lbajardsilogic@0 181 case 0: setBaseColour(Qt::black); break;
lbajardsilogic@0 182 case 1: setBaseColour(Qt::darkRed); break;
lbajardsilogic@0 183 case 2: setBaseColour(Qt::darkBlue); break;
lbajardsilogic@0 184 case 3: setBaseColour(Qt::darkGreen); break;
lbajardsilogic@0 185 case 4: setBaseColour(QColor(200, 50, 255)); break;
lbajardsilogic@0 186 case 5: setBaseColour(QColor(255, 150, 50)); break;
lbajardsilogic@0 187 }
lbajardsilogic@0 188 } else if (name == "Vertical Scale") {
lbajardsilogic@0 189 setVerticalScale(VerticalScale(value));
lbajardsilogic@0 190 } else if (name == "Scale Units") {
lbajardsilogic@0 191 if (m_model) {
lbajardsilogic@0 192 m_model->setScaleUnits
lbajardsilogic@0 193 (UnitDatabase::getInstance()->getUnitById(value));
lbajardsilogic@0 194 emit modelChanged();
lbajardsilogic@0 195 }
lbajardsilogic@0 196 }
lbajardsilogic@0 197 }
lbajardsilogic@0 198
lbajardsilogic@0 199 void
lbajardsilogic@0 200 NoteLayer::setBaseColour(QColor colour)
lbajardsilogic@0 201 {
lbajardsilogic@0 202 if (m_colour == colour) return;
lbajardsilogic@0 203 m_colour = colour;
lbajardsilogic@0 204 emit layerParametersChanged();
lbajardsilogic@0 205 }
lbajardsilogic@0 206
lbajardsilogic@0 207 void
lbajardsilogic@0 208 NoteLayer::setVerticalScale(VerticalScale scale)
lbajardsilogic@0 209 {
lbajardsilogic@0 210 if (m_verticalScale == scale) return;
lbajardsilogic@0 211 m_verticalScale = scale;
lbajardsilogic@0 212 emit layerParametersChanged();
lbajardsilogic@0 213 }
lbajardsilogic@0 214
lbajardsilogic@0 215 bool
lbajardsilogic@0 216 NoteLayer::isLayerScrollable(const View *v) const
lbajardsilogic@0 217 {
lbajardsilogic@0 218 QPoint discard;
lbajardsilogic@0 219 return !v->shouldIlluminateLocalFeatures(this, discard);
lbajardsilogic@0 220 }
lbajardsilogic@0 221
lbajardsilogic@0 222 bool
lbajardsilogic@0 223 NoteLayer::shouldConvertMIDIToHz() const
lbajardsilogic@0 224 {
lbajardsilogic@0 225 QString unit = m_model->getScaleUnits();
lbajardsilogic@0 226 return (unit != "Hz");
lbajardsilogic@0 227 // if (unit == "" ||
lbajardsilogic@0 228 // unit.startsWith("MIDI") ||
lbajardsilogic@0 229 // unit.startsWith("midi")) return true;
lbajardsilogic@0 230 // return false;
lbajardsilogic@0 231 }
lbajardsilogic@0 232
lbajardsilogic@0 233 bool
lbajardsilogic@0 234 NoteLayer::getValueExtents(float &min, float &max,
lbajardsilogic@0 235 bool &logarithmic, QString &unit) const
lbajardsilogic@0 236 {
lbajardsilogic@0 237 if (!m_model) return false;
lbajardsilogic@0 238 min = m_model->getValueMinimum();
lbajardsilogic@0 239 max = m_model->getValueMaximum();
lbajardsilogic@0 240
lbajardsilogic@0 241 if (shouldConvertMIDIToHz()) {
lbajardsilogic@0 242 unit = "Hz";
lbajardsilogic@0 243 min = Pitch::getFrequencyForPitch(lrintf(min));
lbajardsilogic@0 244 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
lbajardsilogic@0 245 } else unit = m_model->getScaleUnits();
lbajardsilogic@0 246
lbajardsilogic@0 247 if (m_verticalScale == MIDIRangeScale ||
lbajardsilogic@0 248 m_verticalScale == LogScale) logarithmic = true;
lbajardsilogic@0 249
lbajardsilogic@0 250 return true;
lbajardsilogic@0 251 }
lbajardsilogic@0 252
lbajardsilogic@0 253 bool
lbajardsilogic@0 254 NoteLayer::getDisplayExtents(float &min, float &max) const
lbajardsilogic@0 255 {
lbajardsilogic@0 256 if (!m_model || m_verticalScale == AutoAlignScale) return false;
lbajardsilogic@0 257
lbajardsilogic@0 258 if (m_verticalScale == MIDIRangeScale) {
lbajardsilogic@0 259 min = Pitch::getFrequencyForPitch(0);
lbajardsilogic@0 260 max = Pitch::getFrequencyForPitch(127);
lbajardsilogic@0 261 return true;
lbajardsilogic@0 262 }
lbajardsilogic@0 263
lbajardsilogic@0 264 min = m_model->getValueMinimum();
lbajardsilogic@0 265 max = m_model->getValueMaximum();
lbajardsilogic@0 266
lbajardsilogic@0 267 if (shouldConvertMIDIToHz()) {
lbajardsilogic@0 268 min = Pitch::getFrequencyForPitch(lrintf(min));
lbajardsilogic@0 269 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
lbajardsilogic@0 270 }
lbajardsilogic@0 271
lbajardsilogic@0 272 return true;
lbajardsilogic@0 273 }
lbajardsilogic@0 274
lbajardsilogic@0 275 NoteModel::PointList
lbajardsilogic@0 276 NoteLayer::getLocalPoints(View *v, int x) const
lbajardsilogic@0 277 {
lbajardsilogic@0 278 if (!m_model) return NoteModel::PointList();
lbajardsilogic@0 279
lbajardsilogic@0 280 long frame = v->getFrameForX(x);
lbajardsilogic@0 281
lbajardsilogic@0 282 NoteModel::PointList onPoints =
lbajardsilogic@0 283 m_model->getPoints(frame);
lbajardsilogic@0 284
lbajardsilogic@0 285 if (!onPoints.empty()) {
lbajardsilogic@0 286 return onPoints;
lbajardsilogic@0 287 }
lbajardsilogic@0 288
lbajardsilogic@0 289 NoteModel::PointList prevPoints =
lbajardsilogic@0 290 m_model->getPreviousPoints(frame);
lbajardsilogic@0 291 NoteModel::PointList nextPoints =
lbajardsilogic@0 292 m_model->getNextPoints(frame);
lbajardsilogic@0 293
lbajardsilogic@0 294 NoteModel::PointList usePoints = prevPoints;
lbajardsilogic@0 295
lbajardsilogic@0 296 if (prevPoints.empty()) {
lbajardsilogic@0 297 usePoints = nextPoints;
lbajardsilogic@0 298 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() &&
lbajardsilogic@0 299 !(nextPoints.begin()->frame > v->getEndFrame())) {
lbajardsilogic@0 300 usePoints = nextPoints;
lbajardsilogic@0 301 } else if (long(nextPoints.begin()->frame) - frame <
lbajardsilogic@0 302 frame - long(prevPoints.begin()->frame)) {
lbajardsilogic@0 303 usePoints = nextPoints;
lbajardsilogic@0 304 }
lbajardsilogic@0 305
lbajardsilogic@0 306 if (!usePoints.empty()) {
lbajardsilogic@0 307 int fuzz = 2;
lbajardsilogic@0 308 int px = v->getXForFrame(usePoints.begin()->frame);
lbajardsilogic@0 309 if ((px > x && px - x > fuzz) ||
lbajardsilogic@0 310 (px < x && x - px > fuzz + 1)) {
lbajardsilogic@0 311 usePoints.clear();
lbajardsilogic@0 312 }
lbajardsilogic@0 313 }
lbajardsilogic@0 314
lbajardsilogic@0 315 return usePoints;
lbajardsilogic@0 316 }
lbajardsilogic@0 317
lbajardsilogic@0 318 QString
lbajardsilogic@0 319 NoteLayer::getFeatureDescription(View *v, QPoint &pos) const
lbajardsilogic@0 320 {
lbajardsilogic@0 321 int x = pos.x();
lbajardsilogic@0 322
lbajardsilogic@0 323 if (!m_model || !m_model->getSampleRate()) return "";
lbajardsilogic@0 324
lbajardsilogic@0 325 NoteModel::PointList points = getLocalPoints(v, x);
lbajardsilogic@0 326
lbajardsilogic@0 327 if (points.empty()) {
lbajardsilogic@0 328 if (!m_model->isReady()) {
lbajardsilogic@0 329 return tr("In progress");
lbajardsilogic@0 330 } else {
lbajardsilogic@0 331 return tr("No local points");
lbajardsilogic@0 332 }
lbajardsilogic@0 333 }
lbajardsilogic@0 334
lbajardsilogic@0 335 Note note(0);
lbajardsilogic@0 336 NoteModel::PointList::iterator i;
lbajardsilogic@0 337
lbajardsilogic@0 338 for (i = points.begin(); i != points.end(); ++i) {
lbajardsilogic@0 339
lbajardsilogic@0 340 int y = getYForValue(v, i->value);
lbajardsilogic@0 341 int h = 3;
lbajardsilogic@0 342
lbajardsilogic@0 343 if (m_model->getValueQuantization() != 0.0) {
lbajardsilogic@0 344 h = y - getYForValue(v, i->value + m_model->getValueQuantization());
lbajardsilogic@0 345 if (h < 3) h = 3;
lbajardsilogic@0 346 }
lbajardsilogic@0 347
lbajardsilogic@0 348 if (pos.y() >= y - h && pos.y() <= y) {
lbajardsilogic@0 349 note = *i;
lbajardsilogic@0 350 break;
lbajardsilogic@0 351 }
lbajardsilogic@0 352 }
lbajardsilogic@0 353
lbajardsilogic@0 354 if (i == points.end()) return tr("No local points");
lbajardsilogic@0 355
lbajardsilogic@0 356 RealTime rt = RealTime::frame2RealTime(note.frame,
lbajardsilogic@0 357 m_model->getSampleRate());
lbajardsilogic@0 358 RealTime rd = RealTime::frame2RealTime(note.duration,
lbajardsilogic@0 359 m_model->getSampleRate());
lbajardsilogic@0 360
lbajardsilogic@0 361 QString pitchText;
lbajardsilogic@0 362
lbajardsilogic@0 363 if (shouldConvertMIDIToHz()) {
lbajardsilogic@0 364
lbajardsilogic@0 365 int mnote = lrintf(note.value);
lbajardsilogic@0 366 int cents = lrintf((note.value - mnote) * 100);
lbajardsilogic@0 367 float freq = Pitch::getFrequencyForPitch(mnote, cents);
lbajardsilogic@0 368 pitchText = tr("%1 (%2 Hz)")
lbajardsilogic@0 369 .arg(Pitch::getPitchLabel(mnote, cents)).arg(freq);
lbajardsilogic@0 370
lbajardsilogic@0 371 } else if (m_model->getScaleUnits() == "Hz") {
lbajardsilogic@0 372
lbajardsilogic@0 373 pitchText = tr("%1 Hz (%2)")
lbajardsilogic@0 374 .arg(note.value)
lbajardsilogic@0 375 .arg(Pitch::getPitchLabelForFrequency(note.value));
lbajardsilogic@0 376
lbajardsilogic@0 377 } else {
lbajardsilogic@0 378 pitchText = tr("%1 %2")
lbajardsilogic@0 379 .arg(note.value).arg(m_model->getScaleUnits());
lbajardsilogic@0 380 }
lbajardsilogic@0 381
lbajardsilogic@0 382 QString text;
lbajardsilogic@0 383
lbajardsilogic@0 384 if (note.label == "") {
lbajardsilogic@0 385 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nNo label"))
lbajardsilogic@0 386 .arg(rt.toText(true).c_str())
lbajardsilogic@0 387 .arg(pitchText)
lbajardsilogic@0 388 .arg(rd.toText(true).c_str());
lbajardsilogic@0 389 } else {
lbajardsilogic@0 390 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nLabel:\t%4"))
lbajardsilogic@0 391 .arg(rt.toText(true).c_str())
lbajardsilogic@0 392 .arg(pitchText)
lbajardsilogic@0 393 .arg(rd.toText(true).c_str())
lbajardsilogic@0 394 .arg(note.label);
lbajardsilogic@0 395 }
lbajardsilogic@0 396
lbajardsilogic@0 397 pos = QPoint(v->getXForFrame(note.frame),
lbajardsilogic@0 398 getYForValue(v, note.value));
lbajardsilogic@0 399 return text;
lbajardsilogic@0 400 }
lbajardsilogic@0 401
lbajardsilogic@0 402 bool
lbajardsilogic@0 403 NoteLayer::snapToFeatureFrame(View *v, int &frame,
lbajardsilogic@0 404 size_t &resolution,
lbajardsilogic@0 405 SnapType snap) const
lbajardsilogic@0 406 {
lbajardsilogic@0 407 if (!m_model) {
lbajardsilogic@0 408 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
lbajardsilogic@0 409 }
lbajardsilogic@0 410
lbajardsilogic@0 411 resolution = m_model->getResolution();
lbajardsilogic@0 412 NoteModel::PointList points;
lbajardsilogic@0 413
lbajardsilogic@0 414 if (snap == SnapNeighbouring) {
lbajardsilogic@0 415
lbajardsilogic@0 416 points = getLocalPoints(v, v->getXForFrame(frame));
lbajardsilogic@0 417 if (points.empty()) return false;
lbajardsilogic@0 418 frame = points.begin()->frame;
lbajardsilogic@0 419 return true;
lbajardsilogic@0 420 }
lbajardsilogic@0 421
lbajardsilogic@0 422 points = m_model->getPoints(frame, frame);
lbajardsilogic@0 423 int snapped = frame;
lbajardsilogic@0 424 bool found = false;
lbajardsilogic@0 425
lbajardsilogic@0 426 for (NoteModel::PointList::const_iterator i = points.begin();
lbajardsilogic@0 427 i != points.end(); ++i) {
lbajardsilogic@0 428
lbajardsilogic@0 429 if (snap == SnapRight) {
lbajardsilogic@0 430
lbajardsilogic@0 431 if (i->frame > frame) {
lbajardsilogic@0 432 snapped = i->frame;
lbajardsilogic@0 433 found = true;
lbajardsilogic@0 434 break;
lbajardsilogic@0 435 }
lbajardsilogic@0 436
lbajardsilogic@0 437 } else if (snap == SnapLeft) {
lbajardsilogic@0 438
lbajardsilogic@0 439 if (i->frame <= frame) {
lbajardsilogic@0 440 snapped = i->frame;
lbajardsilogic@0 441 found = true; // don't break, as the next may be better
lbajardsilogic@0 442 } else {
lbajardsilogic@0 443 break;
lbajardsilogic@0 444 }
lbajardsilogic@0 445
lbajardsilogic@0 446 } else { // nearest
lbajardsilogic@0 447
lbajardsilogic@0 448 NoteModel::PointList::const_iterator j = i;
lbajardsilogic@0 449 ++j;
lbajardsilogic@0 450
lbajardsilogic@0 451 if (j == points.end()) {
lbajardsilogic@0 452
lbajardsilogic@0 453 snapped = i->frame;
lbajardsilogic@0 454 found = true;
lbajardsilogic@0 455 break;
lbajardsilogic@0 456
lbajardsilogic@0 457 } else if (j->frame >= frame) {
lbajardsilogic@0 458
lbajardsilogic@0 459 if (j->frame - frame < frame - i->frame) {
lbajardsilogic@0 460 snapped = j->frame;
lbajardsilogic@0 461 } else {
lbajardsilogic@0 462 snapped = i->frame;
lbajardsilogic@0 463 }
lbajardsilogic@0 464 found = true;
lbajardsilogic@0 465 break;
lbajardsilogic@0 466 }
lbajardsilogic@0 467 }
lbajardsilogic@0 468 }
lbajardsilogic@0 469
lbajardsilogic@0 470 frame = snapped;
lbajardsilogic@0 471 return found;
lbajardsilogic@0 472 }
lbajardsilogic@0 473
lbajardsilogic@0 474 void
lbajardsilogic@0 475 NoteLayer::getScaleExtents(View *v, float &min, float &max, bool &log) const
lbajardsilogic@0 476 {
lbajardsilogic@0 477 min = 0.0;
lbajardsilogic@0 478 max = 0.0;
lbajardsilogic@0 479 log = false;
lbajardsilogic@0 480
lbajardsilogic@0 481 QString queryUnits;
lbajardsilogic@0 482 if (shouldConvertMIDIToHz()) queryUnits = "Hz";
lbajardsilogic@0 483 else queryUnits = m_model->getScaleUnits();
lbajardsilogic@0 484
lbajardsilogic@0 485 if (m_verticalScale == AutoAlignScale) {
lbajardsilogic@0 486
lbajardsilogic@0 487 if (!v->getValueExtents(queryUnits, min, max, log)) {
lbajardsilogic@0 488
lbajardsilogic@0 489 min = m_model->getValueMinimum();
lbajardsilogic@0 490 max = m_model->getValueMaximum();
lbajardsilogic@0 491
lbajardsilogic@0 492 if (shouldConvertMIDIToHz()) {
lbajardsilogic@0 493 min = Pitch::getFrequencyForPitch(lrintf(min));
lbajardsilogic@0 494 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
lbajardsilogic@0 495 }
lbajardsilogic@0 496
lbajardsilogic@0 497 std::cerr << "NoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << std::endl;
lbajardsilogic@0 498
lbajardsilogic@0 499 } else if (log) {
lbajardsilogic@0 500
lbajardsilogic@0 501 LogRange::mapRange(min, max);
lbajardsilogic@0 502
lbajardsilogic@0 503 std::cerr << "NoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << std::endl;
lbajardsilogic@0 504
lbajardsilogic@0 505 }
lbajardsilogic@0 506
lbajardsilogic@0 507 } else {
lbajardsilogic@0 508
lbajardsilogic@0 509 min = m_model->getValueMinimum();
lbajardsilogic@0 510 max = m_model->getValueMaximum();
lbajardsilogic@0 511
lbajardsilogic@0 512 if (m_verticalScale == MIDIRangeScale) {
lbajardsilogic@0 513 min = Pitch::getFrequencyForPitch(0);
lbajardsilogic@0 514 max = Pitch::getFrequencyForPitch(127);
lbajardsilogic@0 515 } else if (shouldConvertMIDIToHz()) {
lbajardsilogic@0 516 min = Pitch::getFrequencyForPitch(lrintf(min));
lbajardsilogic@0 517 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
lbajardsilogic@0 518 }
lbajardsilogic@0 519
lbajardsilogic@0 520 if (m_verticalScale == LogScale || m_verticalScale == MIDIRangeScale) {
lbajardsilogic@0 521 LogRange::mapRange(min, max);
lbajardsilogic@0 522 log = true;
lbajardsilogic@0 523 }
lbajardsilogic@0 524 }
lbajardsilogic@0 525
lbajardsilogic@0 526 if (max == min) max = min + 1.0;
lbajardsilogic@0 527 }
lbajardsilogic@0 528
lbajardsilogic@0 529 int
lbajardsilogic@0 530 NoteLayer::getYForValue(View *v, float val) const
lbajardsilogic@0 531 {
lbajardsilogic@0 532 float min = 0.0, max = 0.0;
lbajardsilogic@0 533 bool logarithmic = false;
lbajardsilogic@0 534 int h = v->height();
lbajardsilogic@0 535
lbajardsilogic@0 536 getScaleExtents(v, min, max, logarithmic);
lbajardsilogic@0 537
lbajardsilogic@0 538 // std::cerr << "NoteLayer[" << this << "]::getYForValue(" << val << "): min = " << min << ", max = " << max << ", log = " << logarithmic << std::endl;
lbajardsilogic@0 539
lbajardsilogic@0 540 if (shouldConvertMIDIToHz()) {
lbajardsilogic@0 541 val = Pitch::getFrequencyForPitch(lrintf(val),
lbajardsilogic@0 542 lrintf((val - lrintf(val)) * 100));
lbajardsilogic@0 543 // std::cerr << "shouldConvertMIDIToHz true, val now = " << val << std::endl;
lbajardsilogic@0 544 }
lbajardsilogic@0 545
lbajardsilogic@0 546 if (logarithmic) {
lbajardsilogic@0 547 val = LogRange::map(val);
lbajardsilogic@0 548 // std::cerr << "logarithmic true, val now = " << val << std::endl;
lbajardsilogic@0 549 }
lbajardsilogic@0 550
lbajardsilogic@0 551 int y = int(h - ((val - min) * h) / (max - min)) - 1;
lbajardsilogic@0 552 // std::cerr << "y = " << y << std::endl;
lbajardsilogic@0 553 return y;
lbajardsilogic@0 554 }
lbajardsilogic@0 555
lbajardsilogic@0 556 float
lbajardsilogic@0 557 NoteLayer::getValueForY(View *v, int y) const
lbajardsilogic@0 558 {
lbajardsilogic@0 559 float min = 0.0, max = 0.0;
lbajardsilogic@0 560 bool logarithmic = false;
lbajardsilogic@0 561 int h = v->height();
lbajardsilogic@0 562
lbajardsilogic@0 563 getScaleExtents(v, min, max, logarithmic);
lbajardsilogic@0 564
lbajardsilogic@0 565 float val = min + (float(h - y) * float(max - min)) / h;
lbajardsilogic@0 566
lbajardsilogic@0 567 if (logarithmic) {
lbajardsilogic@0 568 val = powf(10.f, val);
lbajardsilogic@0 569 }
lbajardsilogic@0 570
lbajardsilogic@0 571 if (shouldConvertMIDIToHz()) {
lbajardsilogic@0 572 val = Pitch::getPitchForFrequency(val);
lbajardsilogic@0 573 }
lbajardsilogic@0 574
lbajardsilogic@0 575 return val;
lbajardsilogic@0 576 }
lbajardsilogic@0 577
lbajardsilogic@0 578 void
lbajardsilogic@0 579 NoteLayer::paint(View *v, QPainter &paint, QRect rect) const
lbajardsilogic@0 580 {
lbajardsilogic@0 581 if (!m_model || !m_model->isOK()) return;
lbajardsilogic@0 582
lbajardsilogic@0 583 int sampleRate = m_model->getSampleRate();
lbajardsilogic@0 584 if (!sampleRate) return;
lbajardsilogic@0 585
lbajardsilogic@0 586 // Profiler profiler("NoteLayer::paint", true);
lbajardsilogic@0 587
lbajardsilogic@0 588 int x0 = rect.left(), x1 = rect.right();
lbajardsilogic@0 589 long frame0 = v->getFrameForX(x0);
lbajardsilogic@0 590 long frame1 = v->getFrameForX(x1);
lbajardsilogic@0 591
lbajardsilogic@0 592 NoteModel::PointList points(m_model->getPoints(frame0, frame1));
lbajardsilogic@0 593 if (points.empty()) return;
lbajardsilogic@0 594
lbajardsilogic@0 595 paint.setPen(m_colour);
lbajardsilogic@0 596
lbajardsilogic@0 597 QColor brushColour(m_colour);
lbajardsilogic@0 598 brushColour.setAlpha(80);
lbajardsilogic@0 599
lbajardsilogic@0 600 // std::cerr << "NoteLayer::paint: resolution is "
lbajardsilogic@0 601 // << m_model->getResolution() << " frames" << std::endl;
lbajardsilogic@0 602
lbajardsilogic@0 603 float min = m_model->getValueMinimum();
lbajardsilogic@0 604 float max = m_model->getValueMaximum();
lbajardsilogic@0 605 if (max == min) max = min + 1.0;
lbajardsilogic@0 606
lbajardsilogic@0 607 QPoint localPos;
lbajardsilogic@0 608 long illuminateFrame = -1;
lbajardsilogic@0 609
lbajardsilogic@0 610 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
lbajardsilogic@0 611 NoteModel::PointList localPoints =
lbajardsilogic@0 612 getLocalPoints(v, localPos.x());
lbajardsilogic@0 613 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
lbajardsilogic@0 614 }
lbajardsilogic@0 615
lbajardsilogic@0 616 paint.save();
lbajardsilogic@0 617 paint.setRenderHint(QPainter::Antialiasing, false);
lbajardsilogic@0 618
lbajardsilogic@0 619 for (NoteModel::PointList::const_iterator i = points.begin();
lbajardsilogic@0 620 i != points.end(); ++i) {
lbajardsilogic@0 621
lbajardsilogic@0 622 const NoteModel::Point &p(*i);
lbajardsilogic@0 623
lbajardsilogic@0 624 int x = v->getXForFrame(p.frame);
lbajardsilogic@0 625 int y = getYForValue(v, p.value);
lbajardsilogic@0 626 int w = v->getXForFrame(p.frame + p.duration) - x;
lbajardsilogic@0 627 int h = 3;
lbajardsilogic@0 628
lbajardsilogic@0 629 if (m_model->getValueQuantization() != 0.0) {
lbajardsilogic@0 630 h = y - getYForValue(v, p.value + m_model->getValueQuantization());
lbajardsilogic@0 631 if (h < 3) h = 3;
lbajardsilogic@0 632 }
lbajardsilogic@0 633
lbajardsilogic@0 634 if (w < 1) w = 1;
lbajardsilogic@0 635 paint.setPen(m_colour);
lbajardsilogic@0 636 paint.setBrush(brushColour);
lbajardsilogic@0 637
lbajardsilogic@0 638 if (illuminateFrame == p.frame) {
lbajardsilogic@0 639 if (localPos.y() >= y - h && localPos.y() < y) {
lbajardsilogic@0 640 paint.setPen(Qt::black);//!!!
lbajardsilogic@0 641 paint.setBrush(Qt::black);//!!!
lbajardsilogic@0 642 }
lbajardsilogic@0 643 }
lbajardsilogic@0 644
lbajardsilogic@0 645 paint.drawRect(x, y - h/2, w, h);
lbajardsilogic@0 646
lbajardsilogic@0 647 /// if (p.label != "") {
lbajardsilogic@0 648 /// paint.drawText(x + 5, y - paint.fontMetrics().height() + paint.fontMetrics().ascent(), p.label);
lbajardsilogic@0 649 /// }
lbajardsilogic@0 650 }
lbajardsilogic@0 651
lbajardsilogic@0 652 paint.restore();
lbajardsilogic@0 653 }
lbajardsilogic@0 654
lbajardsilogic@0 655 void
lbajardsilogic@0 656 NoteLayer::drawStart(View *v, QMouseEvent *e)
lbajardsilogic@0 657 {
lbajardsilogic@0 658 // std::cerr << "NoteLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 659
lbajardsilogic@0 660 if (!m_model) return;
lbajardsilogic@0 661
lbajardsilogic@0 662 long frame = v->getFrameForX(e->x());
lbajardsilogic@0 663 if (frame < 0) frame = 0;
lbajardsilogic@0 664 frame = frame / m_model->getResolution() * m_model->getResolution();
lbajardsilogic@0 665
lbajardsilogic@0 666 float value = getValueForY(v, e->y());
lbajardsilogic@0 667
lbajardsilogic@0 668 m_editingPoint = NoteModel::Point(frame, value, 0, tr("New Point"));
lbajardsilogic@0 669 m_originalPoint = m_editingPoint;
lbajardsilogic@0 670
lbajardsilogic@0 671 if (m_editingCommand) m_editingCommand->finish();
lbajardsilogic@0 672 m_editingCommand = new NoteModel::EditCommand(m_model,
lbajardsilogic@0 673 tr("Draw Point"));
lbajardsilogic@0 674 m_editingCommand->addPoint(m_editingPoint);
lbajardsilogic@0 675
lbajardsilogic@0 676 m_editing = true;
lbajardsilogic@0 677 }
lbajardsilogic@0 678
lbajardsilogic@0 679 void
lbajardsilogic@0 680 NoteLayer::drawDrag(View *v, QMouseEvent *e)
lbajardsilogic@0 681 {
lbajardsilogic@0 682 // std::cerr << "NoteLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 683
lbajardsilogic@0 684 if (!m_model || !m_editing) return;
lbajardsilogic@0 685
lbajardsilogic@0 686 long frame = v->getFrameForX(e->x());
lbajardsilogic@0 687 if (frame < 0) frame = 0;
lbajardsilogic@0 688 frame = frame / m_model->getResolution() * m_model->getResolution();
lbajardsilogic@0 689
lbajardsilogic@0 690 float newValue = getValueForY(v, e->y());
lbajardsilogic@0 691
lbajardsilogic@0 692 long newFrame = m_editingPoint.frame;
lbajardsilogic@0 693 long newDuration = frame - newFrame;
lbajardsilogic@0 694 if (newDuration < 0) {
lbajardsilogic@0 695 newFrame = frame;
lbajardsilogic@0 696 newDuration = -newDuration;
lbajardsilogic@0 697 } else if (newDuration == 0) {
lbajardsilogic@0 698 newDuration = 1;
lbajardsilogic@0 699 }
lbajardsilogic@0 700
lbajardsilogic@0 701 m_editingCommand->deletePoint(m_editingPoint);
lbajardsilogic@0 702 m_editingPoint.frame = newFrame;
lbajardsilogic@0 703 m_editingPoint.value = newValue;
lbajardsilogic@0 704 m_editingPoint.duration = newDuration;
lbajardsilogic@0 705 m_editingCommand->addPoint(m_editingPoint);
lbajardsilogic@0 706 }
lbajardsilogic@0 707
lbajardsilogic@0 708 void
lbajardsilogic@0 709 NoteLayer::drawEnd(View *, QMouseEvent *)
lbajardsilogic@0 710 {
lbajardsilogic@0 711 // std::cerr << "NoteLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 712 if (!m_model || !m_editing) return;
lbajardsilogic@0 713 m_editingCommand->finish();
lbajardsilogic@0 714 m_editingCommand = 0;
lbajardsilogic@0 715 m_editing = false;
lbajardsilogic@0 716 }
lbajardsilogic@0 717
lbajardsilogic@0 718 void
lbajardsilogic@0 719 NoteLayer::editStart(View *v, QMouseEvent *e)
lbajardsilogic@0 720 {
lbajardsilogic@0 721 // std::cerr << "NoteLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 722
lbajardsilogic@0 723 if (!m_model) return;
lbajardsilogic@0 724
lbajardsilogic@0 725 NoteModel::PointList points = getLocalPoints(v, e->x());
lbajardsilogic@0 726 if (points.empty()) return;
lbajardsilogic@0 727
lbajardsilogic@0 728 m_editingPoint = *points.begin();
lbajardsilogic@0 729 m_originalPoint = m_editingPoint;
lbajardsilogic@0 730
lbajardsilogic@0 731 if (m_editingCommand) {
lbajardsilogic@0 732 m_editingCommand->finish();
lbajardsilogic@0 733 m_editingCommand = 0;
lbajardsilogic@0 734 }
lbajardsilogic@0 735
lbajardsilogic@0 736 m_editing = true;
lbajardsilogic@0 737 }
lbajardsilogic@0 738
lbajardsilogic@0 739 void
lbajardsilogic@0 740 NoteLayer::editDrag(View *v, QMouseEvent *e)
lbajardsilogic@0 741 {
lbajardsilogic@0 742 // std::cerr << "NoteLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 743
lbajardsilogic@0 744 if (!m_model || !m_editing) return;
lbajardsilogic@0 745
lbajardsilogic@0 746 long frame = v->getFrameForX(e->x());
lbajardsilogic@0 747 if (frame < 0) frame = 0;
lbajardsilogic@0 748 frame = frame / m_model->getResolution() * m_model->getResolution();
lbajardsilogic@0 749
lbajardsilogic@0 750 float value = getValueForY(v, e->y());
lbajardsilogic@0 751
lbajardsilogic@0 752 if (!m_editingCommand) {
lbajardsilogic@0 753 m_editingCommand = new NoteModel::EditCommand(m_model,
lbajardsilogic@0 754 tr("Drag Point"));
lbajardsilogic@0 755 }
lbajardsilogic@0 756
lbajardsilogic@0 757 m_editingCommand->deletePoint(m_editingPoint);
lbajardsilogic@0 758 m_editingPoint.frame = frame;
lbajardsilogic@0 759 m_editingPoint.value = value;
lbajardsilogic@0 760 m_editingCommand->addPoint(m_editingPoint);
lbajardsilogic@0 761 }
lbajardsilogic@0 762
lbajardsilogic@0 763 void
lbajardsilogic@0 764 NoteLayer::editEnd(View *, QMouseEvent *)
lbajardsilogic@0 765 {
lbajardsilogic@0 766 // std::cerr << "NoteLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 767 if (!m_model || !m_editing) return;
lbajardsilogic@0 768
lbajardsilogic@0 769 if (m_editingCommand) {
lbajardsilogic@0 770
lbajardsilogic@0 771 QString newName = m_editingCommand->getName();
lbajardsilogic@0 772
lbajardsilogic@0 773 if (m_editingPoint.frame != m_originalPoint.frame) {
lbajardsilogic@0 774 if (m_editingPoint.value != m_originalPoint.value) {
lbajardsilogic@0 775 newName = tr("Edit Point");
lbajardsilogic@0 776 } else {
lbajardsilogic@0 777 newName = tr("Relocate Point");
lbajardsilogic@0 778 }
lbajardsilogic@0 779 } else {
lbajardsilogic@0 780 newName = tr("Change Point Value");
lbajardsilogic@0 781 }
lbajardsilogic@0 782
lbajardsilogic@0 783 m_editingCommand->setName(newName);
lbajardsilogic@0 784 m_editingCommand->finish();
lbajardsilogic@0 785 }
lbajardsilogic@0 786
lbajardsilogic@0 787 m_editingCommand = 0;
lbajardsilogic@0 788 m_editing = false;
lbajardsilogic@0 789 }
lbajardsilogic@0 790
lbajardsilogic@0 791 void
lbajardsilogic@0 792 NoteLayer::editOpen(View *v, QMouseEvent *e)
lbajardsilogic@0 793 {
lbajardsilogic@0 794 if (!m_model) return;
lbajardsilogic@0 795
lbajardsilogic@0 796 NoteModel::PointList points = getLocalPoints(v, e->x());
lbajardsilogic@0 797 if (points.empty()) return;
lbajardsilogic@0 798
lbajardsilogic@0 799 NoteModel::Point note = *points.begin();
lbajardsilogic@0 800
lbajardsilogic@0 801 ItemEditDialog *dialog = new ItemEditDialog
lbajardsilogic@0 802 (m_model->getSampleRate(),
lbajardsilogic@0 803 ItemEditDialog::ShowTime |
lbajardsilogic@0 804 ItemEditDialog::ShowDuration |
lbajardsilogic@0 805 ItemEditDialog::ShowValue |
lbajardsilogic@0 806 ItemEditDialog::ShowText,
lbajardsilogic@0 807 m_model->getScaleUnits());
lbajardsilogic@0 808
lbajardsilogic@0 809 dialog->setFrameTime(note.frame);
lbajardsilogic@0 810 dialog->setValue(note.value);
lbajardsilogic@0 811 dialog->setFrameDuration(note.duration);
lbajardsilogic@0 812 dialog->setText(note.label);
lbajardsilogic@0 813
lbajardsilogic@0 814 if (dialog->exec() == QDialog::Accepted) {
lbajardsilogic@0 815
lbajardsilogic@0 816 NoteModel::Point newNote = note;
lbajardsilogic@0 817 newNote.frame = dialog->getFrameTime();
lbajardsilogic@0 818 newNote.value = dialog->getValue();
lbajardsilogic@0 819 newNote.duration = dialog->getFrameDuration();
lbajardsilogic@0 820 newNote.label = dialog->getText();
lbajardsilogic@0 821
lbajardsilogic@0 822 NoteModel::EditCommand *command = new NoteModel::EditCommand
lbajardsilogic@0 823 (m_model, tr("Edit Point"));
lbajardsilogic@0 824 command->deletePoint(note);
lbajardsilogic@0 825 command->addPoint(newNote);
lbajardsilogic@0 826 command->finish();
lbajardsilogic@0 827 }
lbajardsilogic@0 828
lbajardsilogic@0 829 delete dialog;
lbajardsilogic@0 830 }
lbajardsilogic@0 831
lbajardsilogic@0 832 void
lbajardsilogic@0 833 NoteLayer::moveSelection(Selection s, size_t newStartFrame)
lbajardsilogic@0 834 {
lbajardsilogic@0 835 if (!m_model) return;
lbajardsilogic@0 836
lbajardsilogic@0 837 NoteModel::EditCommand *command =
lbajardsilogic@0 838 new NoteModel::EditCommand(m_model, tr("Drag Selection"));
lbajardsilogic@0 839
lbajardsilogic@0 840 NoteModel::PointList points =
lbajardsilogic@0 841 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 842
lbajardsilogic@0 843 for (NoteModel::PointList::iterator i = points.begin();
lbajardsilogic@0 844 i != points.end(); ++i) {
lbajardsilogic@0 845
lbajardsilogic@0 846 if (s.contains(i->frame)) {
lbajardsilogic@0 847 NoteModel::Point newPoint(*i);
lbajardsilogic@0 848 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
lbajardsilogic@0 849 command->deletePoint(*i);
lbajardsilogic@0 850 command->addPoint(newPoint);
lbajardsilogic@0 851 }
lbajardsilogic@0 852 }
lbajardsilogic@0 853
lbajardsilogic@0 854 command->finish();
lbajardsilogic@0 855 }
lbajardsilogic@0 856
lbajardsilogic@0 857 void
lbajardsilogic@0 858 NoteLayer::resizeSelection(Selection s, Selection newSize)
lbajardsilogic@0 859 {
lbajardsilogic@0 860 if (!m_model) return;
lbajardsilogic@0 861
lbajardsilogic@0 862 NoteModel::EditCommand *command =
lbajardsilogic@0 863 new NoteModel::EditCommand(m_model, tr("Resize Selection"));
lbajardsilogic@0 864
lbajardsilogic@0 865 NoteModel::PointList points =
lbajardsilogic@0 866 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 867
lbajardsilogic@0 868 double ratio =
lbajardsilogic@0 869 double(newSize.getEndFrame() - newSize.getStartFrame()) /
lbajardsilogic@0 870 double(s.getEndFrame() - s.getStartFrame());
lbajardsilogic@0 871
lbajardsilogic@0 872 for (NoteModel::PointList::iterator i = points.begin();
lbajardsilogic@0 873 i != points.end(); ++i) {
lbajardsilogic@0 874
lbajardsilogic@0 875 if (s.contains(i->frame)) {
lbajardsilogic@0 876
lbajardsilogic@0 877 double targetStart = i->frame;
lbajardsilogic@0 878 targetStart = newSize.getStartFrame() +
lbajardsilogic@0 879 double(targetStart - s.getStartFrame()) * ratio;
lbajardsilogic@0 880
lbajardsilogic@0 881 double targetEnd = i->frame + i->duration;
lbajardsilogic@0 882 targetEnd = newSize.getStartFrame() +
lbajardsilogic@0 883 double(targetEnd - s.getStartFrame()) * ratio;
lbajardsilogic@0 884
lbajardsilogic@0 885 NoteModel::Point newPoint(*i);
lbajardsilogic@0 886 newPoint.frame = lrint(targetStart);
lbajardsilogic@0 887 newPoint.duration = lrint(targetEnd - targetStart);
lbajardsilogic@0 888 command->deletePoint(*i);
lbajardsilogic@0 889 command->addPoint(newPoint);
lbajardsilogic@0 890 }
lbajardsilogic@0 891 }
lbajardsilogic@0 892
lbajardsilogic@0 893 command->finish();
lbajardsilogic@0 894 }
lbajardsilogic@0 895
lbajardsilogic@0 896 void
lbajardsilogic@0 897 NoteLayer::deleteSelection(Selection s)
lbajardsilogic@0 898 {
lbajardsilogic@0 899 if (!m_model) return;
lbajardsilogic@0 900
lbajardsilogic@0 901 NoteModel::EditCommand *command =
lbajardsilogic@0 902 new NoteModel::EditCommand(m_model, tr("Delete Selected Points"));
lbajardsilogic@0 903
lbajardsilogic@0 904 NoteModel::PointList points =
lbajardsilogic@0 905 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 906
lbajardsilogic@0 907 for (NoteModel::PointList::iterator i = points.begin();
lbajardsilogic@0 908 i != points.end(); ++i) {
lbajardsilogic@0 909
lbajardsilogic@0 910 if (s.contains(i->frame)) {
lbajardsilogic@0 911 command->deletePoint(*i);
lbajardsilogic@0 912 }
lbajardsilogic@0 913 }
lbajardsilogic@0 914
lbajardsilogic@0 915 command->finish();
lbajardsilogic@0 916 }
lbajardsilogic@0 917
lbajardsilogic@0 918 void
lbajardsilogic@0 919 NoteLayer::copy(Selection s, Clipboard &to)
lbajardsilogic@0 920 {
lbajardsilogic@0 921 if (!m_model) return;
lbajardsilogic@0 922
lbajardsilogic@0 923 NoteModel::PointList points =
lbajardsilogic@0 924 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 925
lbajardsilogic@0 926 for (NoteModel::PointList::iterator i = points.begin();
lbajardsilogic@0 927 i != points.end(); ++i) {
lbajardsilogic@0 928 if (s.contains(i->frame)) {
lbajardsilogic@0 929 Clipboard::Point point(i->frame, i->value, i->duration, i->label);
lbajardsilogic@0 930 to.addPoint(point);
lbajardsilogic@0 931 }
lbajardsilogic@0 932 }
lbajardsilogic@0 933 }
lbajardsilogic@0 934
lbajardsilogic@0 935 bool
lbajardsilogic@0 936 NoteLayer::paste(const Clipboard &from, int frameOffset, bool /* interactive */)
lbajardsilogic@0 937 {
lbajardsilogic@0 938 if (!m_model) return false;
lbajardsilogic@0 939
lbajardsilogic@0 940 const Clipboard::PointList &points = from.getPoints();
lbajardsilogic@0 941
lbajardsilogic@0 942 NoteModel::EditCommand *command =
lbajardsilogic@0 943 new NoteModel::EditCommand(m_model, tr("Paste"));
lbajardsilogic@0 944
lbajardsilogic@0 945 for (Clipboard::PointList::const_iterator i = points.begin();
lbajardsilogic@0 946 i != points.end(); ++i) {
lbajardsilogic@0 947
lbajardsilogic@0 948 if (!i->haveFrame()) continue;
lbajardsilogic@0 949 size_t frame = 0;
lbajardsilogic@0 950 if (frameOffset > 0 || -frameOffset < i->getFrame()) {
lbajardsilogic@0 951 frame = i->getFrame() + frameOffset;
lbajardsilogic@0 952 }
lbajardsilogic@0 953 NoteModel::Point newPoint(frame);
lbajardsilogic@0 954
lbajardsilogic@0 955 if (i->haveLabel()) newPoint.label = i->getLabel();
lbajardsilogic@0 956 if (i->haveValue()) newPoint.value = i->getValue();
lbajardsilogic@0 957 else newPoint.value = (m_model->getValueMinimum() +
lbajardsilogic@0 958 m_model->getValueMaximum()) / 2;
lbajardsilogic@0 959 if (i->haveDuration()) newPoint.duration = i->getDuration();
lbajardsilogic@0 960 else {
lbajardsilogic@0 961 size_t nextFrame = frame;
lbajardsilogic@0 962 Clipboard::PointList::const_iterator j = i;
lbajardsilogic@0 963 for (; j != points.end(); ++j) {
lbajardsilogic@0 964 if (!j->haveFrame()) continue;
lbajardsilogic@0 965 if (j != i) break;
lbajardsilogic@0 966 }
lbajardsilogic@0 967 if (j != points.end()) {
lbajardsilogic@0 968 nextFrame = j->getFrame();
lbajardsilogic@0 969 }
lbajardsilogic@0 970 if (nextFrame == frame) {
lbajardsilogic@0 971 newPoint.duration = m_model->getResolution();
lbajardsilogic@0 972 } else {
lbajardsilogic@0 973 newPoint.duration = nextFrame - frame;
lbajardsilogic@0 974 }
lbajardsilogic@0 975 }
lbajardsilogic@0 976
lbajardsilogic@0 977 command->addPoint(newPoint);
lbajardsilogic@0 978 }
lbajardsilogic@0 979
lbajardsilogic@0 980 command->finish();
lbajardsilogic@0 981 return true;
lbajardsilogic@0 982 }
lbajardsilogic@0 983
lbajardsilogic@0 984 QString
lbajardsilogic@0 985 NoteLayer::toXmlString(QString indent, QString extraAttributes) const
lbajardsilogic@0 986 {
lbajardsilogic@0 987 return Layer::toXmlString(indent, extraAttributes +
lbajardsilogic@0 988 QString(" colour=\"%1\" verticalScale=\"%2\"")
lbajardsilogic@0 989 .arg(encodeColour(m_colour)).arg(m_verticalScale));
lbajardsilogic@0 990 }
lbajardsilogic@0 991
lbajardsilogic@0 992 void
lbajardsilogic@0 993 NoteLayer::setProperties(const QXmlAttributes &attributes)
lbajardsilogic@0 994 {
lbajardsilogic@0 995 QString colourSpec = attributes.value("colour");
lbajardsilogic@0 996 if (colourSpec != "") {
lbajardsilogic@0 997 QColor colour(colourSpec);
lbajardsilogic@0 998 if (colour.isValid()) {
lbajardsilogic@0 999 setBaseColour(QColor(colourSpec));
lbajardsilogic@0 1000 }
lbajardsilogic@0 1001 }
lbajardsilogic@0 1002
lbajardsilogic@0 1003 bool ok;
lbajardsilogic@0 1004 VerticalScale scale = (VerticalScale)
lbajardsilogic@0 1005 attributes.value("verticalScale").toInt(&ok);
lbajardsilogic@0 1006 if (ok) setVerticalScale(scale);
lbajardsilogic@0 1007 }
lbajardsilogic@0 1008
lbajardsilogic@0 1009