annotate layer/NoteLayer.cpp @ 282:d9319859a4cf tip

(none)
author benoitrigolleau
date Fri, 31 Oct 2008 11:00:24 +0000
parents aa81e87c8089
children
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@34 296 if (! nextPoints.empty())
lbajardsilogic@34 297 {
lbajardsilogic@34 298 if (prevPoints.empty()) {
lbajardsilogic@34 299 usePoints = nextPoints;
lbajardsilogic@34 300 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() &&
lbajardsilogic@34 301 !(nextPoints.begin()->frame > v->getEndFrame())) {
lbajardsilogic@34 302 usePoints = nextPoints;
lbajardsilogic@34 303 } else if (long(nextPoints.begin()->frame) - frame <
lbajardsilogic@34 304 frame - long(prevPoints.begin()->frame)) {
lbajardsilogic@34 305 usePoints = nextPoints;
lbajardsilogic@34 306 }
lbajardsilogic@34 307 }
lbajardsilogic@0 308
lbajardsilogic@0 309 if (!usePoints.empty()) {
lbajardsilogic@0 310 int fuzz = 2;
lbajardsilogic@0 311 int px = v->getXForFrame(usePoints.begin()->frame);
lbajardsilogic@0 312 if ((px > x && px - x > fuzz) ||
lbajardsilogic@0 313 (px < x && x - px > fuzz + 1)) {
lbajardsilogic@0 314 usePoints.clear();
lbajardsilogic@0 315 }
lbajardsilogic@0 316 }
lbajardsilogic@0 317
lbajardsilogic@0 318 return usePoints;
lbajardsilogic@0 319 }
lbajardsilogic@0 320
lbajardsilogic@0 321 QString
lbajardsilogic@0 322 NoteLayer::getFeatureDescription(View *v, QPoint &pos) const
lbajardsilogic@0 323 {
lbajardsilogic@0 324 int x = pos.x();
lbajardsilogic@0 325
lbajardsilogic@0 326 if (!m_model || !m_model->getSampleRate()) return "";
lbajardsilogic@0 327
lbajardsilogic@0 328 NoteModel::PointList points = getLocalPoints(v, x);
lbajardsilogic@0 329
lbajardsilogic@0 330 if (points.empty()) {
lbajardsilogic@0 331 if (!m_model->isReady()) {
lbajardsilogic@0 332 return tr("In progress");
lbajardsilogic@0 333 } else {
lbajardsilogic@0 334 return tr("No local points");
lbajardsilogic@0 335 }
lbajardsilogic@0 336 }
lbajardsilogic@0 337
lbajardsilogic@0 338 Note note(0);
lbajardsilogic@0 339 NoteModel::PointList::iterator i;
lbajardsilogic@0 340
lbajardsilogic@0 341 for (i = points.begin(); i != points.end(); ++i) {
lbajardsilogic@0 342
lbajardsilogic@0 343 int y = getYForValue(v, i->value);
lbajardsilogic@0 344 int h = 3;
lbajardsilogic@0 345
lbajardsilogic@0 346 if (m_model->getValueQuantization() != 0.0) {
lbajardsilogic@0 347 h = y - getYForValue(v, i->value + m_model->getValueQuantization());
lbajardsilogic@0 348 if (h < 3) h = 3;
lbajardsilogic@0 349 }
lbajardsilogic@0 350
lbajardsilogic@0 351 if (pos.y() >= y - h && pos.y() <= y) {
lbajardsilogic@0 352 note = *i;
lbajardsilogic@0 353 break;
lbajardsilogic@0 354 }
lbajardsilogic@0 355 }
lbajardsilogic@0 356
lbajardsilogic@0 357 if (i == points.end()) return tr("No local points");
lbajardsilogic@0 358
lbajardsilogic@0 359 RealTime rt = RealTime::frame2RealTime(note.frame,
lbajardsilogic@0 360 m_model->getSampleRate());
lbajardsilogic@0 361 RealTime rd = RealTime::frame2RealTime(note.duration,
lbajardsilogic@0 362 m_model->getSampleRate());
lbajardsilogic@0 363
lbajardsilogic@0 364 QString pitchText;
lbajardsilogic@0 365
lbajardsilogic@0 366 if (shouldConvertMIDIToHz()) {
lbajardsilogic@0 367
lbajardsilogic@0 368 int mnote = lrintf(note.value);
lbajardsilogic@0 369 int cents = lrintf((note.value - mnote) * 100);
lbajardsilogic@0 370 float freq = Pitch::getFrequencyForPitch(mnote, cents);
lbajardsilogic@0 371 pitchText = tr("%1 (%2 Hz)")
lbajardsilogic@0 372 .arg(Pitch::getPitchLabel(mnote, cents)).arg(freq);
lbajardsilogic@0 373
lbajardsilogic@0 374 } else if (m_model->getScaleUnits() == "Hz") {
lbajardsilogic@0 375
lbajardsilogic@0 376 pitchText = tr("%1 Hz (%2)")
lbajardsilogic@0 377 .arg(note.value)
lbajardsilogic@0 378 .arg(Pitch::getPitchLabelForFrequency(note.value));
lbajardsilogic@0 379
lbajardsilogic@0 380 } else {
lbajardsilogic@0 381 pitchText = tr("%1 %2")
lbajardsilogic@0 382 .arg(note.value).arg(m_model->getScaleUnits());
lbajardsilogic@0 383 }
lbajardsilogic@0 384
lbajardsilogic@0 385 QString text;
lbajardsilogic@0 386
lbajardsilogic@0 387 if (note.label == "") {
lbajardsilogic@0 388 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nNo label"))
lbajardsilogic@0 389 .arg(rt.toText(true).c_str())
lbajardsilogic@0 390 .arg(pitchText)
lbajardsilogic@0 391 .arg(rd.toText(true).c_str());
lbajardsilogic@0 392 } else {
lbajardsilogic@0 393 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nLabel:\t%4"))
lbajardsilogic@0 394 .arg(rt.toText(true).c_str())
lbajardsilogic@0 395 .arg(pitchText)
lbajardsilogic@0 396 .arg(rd.toText(true).c_str())
lbajardsilogic@0 397 .arg(note.label);
lbajardsilogic@0 398 }
lbajardsilogic@0 399
lbajardsilogic@0 400 pos = QPoint(v->getXForFrame(note.frame),
lbajardsilogic@0 401 getYForValue(v, note.value));
lbajardsilogic@0 402 return text;
lbajardsilogic@0 403 }
lbajardsilogic@0 404
lbajardsilogic@0 405 bool
lbajardsilogic@0 406 NoteLayer::snapToFeatureFrame(View *v, int &frame,
lbajardsilogic@0 407 size_t &resolution,
lbajardsilogic@0 408 SnapType snap) const
lbajardsilogic@0 409 {
lbajardsilogic@0 410 if (!m_model) {
lbajardsilogic@0 411 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
lbajardsilogic@0 412 }
lbajardsilogic@0 413
lbajardsilogic@0 414 resolution = m_model->getResolution();
lbajardsilogic@0 415 NoteModel::PointList points;
lbajardsilogic@0 416
lbajardsilogic@0 417 if (snap == SnapNeighbouring) {
lbajardsilogic@0 418
lbajardsilogic@0 419 points = getLocalPoints(v, v->getXForFrame(frame));
lbajardsilogic@0 420 if (points.empty()) return false;
lbajardsilogic@0 421 frame = points.begin()->frame;
lbajardsilogic@0 422 return true;
lbajardsilogic@0 423 }
lbajardsilogic@0 424
lbajardsilogic@0 425 points = m_model->getPoints(frame, frame);
lbajardsilogic@0 426 int snapped = frame;
lbajardsilogic@0 427 bool found = false;
lbajardsilogic@0 428
lbajardsilogic@0 429 for (NoteModel::PointList::const_iterator i = points.begin();
lbajardsilogic@0 430 i != points.end(); ++i) {
lbajardsilogic@0 431
lbajardsilogic@0 432 if (snap == SnapRight) {
lbajardsilogic@0 433
lbajardsilogic@0 434 if (i->frame > frame) {
lbajardsilogic@0 435 snapped = i->frame;
lbajardsilogic@0 436 found = true;
lbajardsilogic@0 437 break;
lbajardsilogic@0 438 }
lbajardsilogic@0 439
lbajardsilogic@0 440 } else if (snap == SnapLeft) {
lbajardsilogic@0 441
lbajardsilogic@0 442 if (i->frame <= frame) {
lbajardsilogic@0 443 snapped = i->frame;
lbajardsilogic@0 444 found = true; // don't break, as the next may be better
lbajardsilogic@0 445 } else {
lbajardsilogic@0 446 break;
lbajardsilogic@0 447 }
lbajardsilogic@0 448
lbajardsilogic@0 449 } else { // nearest
lbajardsilogic@0 450
lbajardsilogic@0 451 NoteModel::PointList::const_iterator j = i;
lbajardsilogic@0 452 ++j;
lbajardsilogic@0 453
lbajardsilogic@0 454 if (j == points.end()) {
lbajardsilogic@0 455
lbajardsilogic@0 456 snapped = i->frame;
lbajardsilogic@0 457 found = true;
lbajardsilogic@0 458 break;
lbajardsilogic@0 459
lbajardsilogic@0 460 } else if (j->frame >= frame) {
lbajardsilogic@0 461
lbajardsilogic@0 462 if (j->frame - frame < frame - i->frame) {
lbajardsilogic@0 463 snapped = j->frame;
lbajardsilogic@0 464 } else {
lbajardsilogic@0 465 snapped = i->frame;
lbajardsilogic@0 466 }
lbajardsilogic@0 467 found = true;
lbajardsilogic@0 468 break;
lbajardsilogic@0 469 }
lbajardsilogic@0 470 }
lbajardsilogic@0 471 }
lbajardsilogic@0 472
lbajardsilogic@0 473 frame = snapped;
lbajardsilogic@0 474 return found;
lbajardsilogic@0 475 }
lbajardsilogic@0 476
lbajardsilogic@0 477 void
lbajardsilogic@0 478 NoteLayer::getScaleExtents(View *v, float &min, float &max, bool &log) const
lbajardsilogic@0 479 {
lbajardsilogic@0 480 min = 0.0;
lbajardsilogic@0 481 max = 0.0;
lbajardsilogic@0 482 log = false;
lbajardsilogic@0 483
lbajardsilogic@0 484 QString queryUnits;
lbajardsilogic@0 485 if (shouldConvertMIDIToHz()) queryUnits = "Hz";
lbajardsilogic@0 486 else queryUnits = m_model->getScaleUnits();
lbajardsilogic@0 487
lbajardsilogic@0 488 if (m_verticalScale == AutoAlignScale) {
lbajardsilogic@0 489
lbajardsilogic@0 490 if (!v->getValueExtents(queryUnits, min, max, log)) {
lbajardsilogic@0 491
lbajardsilogic@0 492 min = m_model->getValueMinimum();
lbajardsilogic@0 493 max = m_model->getValueMaximum();
lbajardsilogic@0 494
lbajardsilogic@0 495 if (shouldConvertMIDIToHz()) {
lbajardsilogic@0 496 min = Pitch::getFrequencyForPitch(lrintf(min));
lbajardsilogic@0 497 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
lbajardsilogic@0 498 }
lbajardsilogic@0 499
lbajardsilogic@0 500 std::cerr << "NoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << std::endl;
lbajardsilogic@0 501
lbajardsilogic@0 502 } else if (log) {
lbajardsilogic@0 503
lbajardsilogic@0 504 LogRange::mapRange(min, max);
lbajardsilogic@0 505
lbajardsilogic@0 506 std::cerr << "NoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << std::endl;
lbajardsilogic@0 507
lbajardsilogic@0 508 }
lbajardsilogic@0 509
lbajardsilogic@0 510 } else {
lbajardsilogic@0 511
lbajardsilogic@0 512 min = m_model->getValueMinimum();
lbajardsilogic@0 513 max = m_model->getValueMaximum();
lbajardsilogic@0 514
lbajardsilogic@0 515 if (m_verticalScale == MIDIRangeScale) {
lbajardsilogic@0 516 min = Pitch::getFrequencyForPitch(0);
lbajardsilogic@0 517 max = Pitch::getFrequencyForPitch(127);
lbajardsilogic@0 518 } else if (shouldConvertMIDIToHz()) {
lbajardsilogic@0 519 min = Pitch::getFrequencyForPitch(lrintf(min));
lbajardsilogic@0 520 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
lbajardsilogic@0 521 }
lbajardsilogic@0 522
lbajardsilogic@0 523 if (m_verticalScale == LogScale || m_verticalScale == MIDIRangeScale) {
lbajardsilogic@0 524 LogRange::mapRange(min, max);
lbajardsilogic@0 525 log = true;
lbajardsilogic@0 526 }
lbajardsilogic@0 527 }
lbajardsilogic@0 528
lbajardsilogic@0 529 if (max == min) max = min + 1.0;
lbajardsilogic@0 530 }
lbajardsilogic@0 531
lbajardsilogic@0 532 int
lbajardsilogic@0 533 NoteLayer::getYForValue(View *v, float val) const
lbajardsilogic@0 534 {
lbajardsilogic@0 535 float min = 0.0, max = 0.0;
lbajardsilogic@0 536 bool logarithmic = false;
lbajardsilogic@0 537 int h = v->height();
lbajardsilogic@0 538
lbajardsilogic@0 539 getScaleExtents(v, min, max, logarithmic);
lbajardsilogic@0 540
lbajardsilogic@0 541 // std::cerr << "NoteLayer[" << this << "]::getYForValue(" << val << "): min = " << min << ", max = " << max << ", log = " << logarithmic << std::endl;
lbajardsilogic@0 542
lbajardsilogic@0 543 if (shouldConvertMIDIToHz()) {
lbajardsilogic@0 544 val = Pitch::getFrequencyForPitch(lrintf(val),
lbajardsilogic@0 545 lrintf((val - lrintf(val)) * 100));
lbajardsilogic@0 546 // std::cerr << "shouldConvertMIDIToHz true, val now = " << val << std::endl;
lbajardsilogic@0 547 }
lbajardsilogic@0 548
lbajardsilogic@0 549 if (logarithmic) {
lbajardsilogic@0 550 val = LogRange::map(val);
lbajardsilogic@0 551 // std::cerr << "logarithmic true, val now = " << val << std::endl;
lbajardsilogic@0 552 }
lbajardsilogic@0 553
lbajardsilogic@0 554 int y = int(h - ((val - min) * h) / (max - min)) - 1;
lbajardsilogic@0 555 // std::cerr << "y = " << y << std::endl;
lbajardsilogic@0 556 return y;
lbajardsilogic@0 557 }
lbajardsilogic@0 558
lbajardsilogic@0 559 float
lbajardsilogic@0 560 NoteLayer::getValueForY(View *v, int y) const
lbajardsilogic@0 561 {
lbajardsilogic@0 562 float min = 0.0, max = 0.0;
lbajardsilogic@0 563 bool logarithmic = false;
lbajardsilogic@0 564 int h = v->height();
lbajardsilogic@0 565
lbajardsilogic@0 566 getScaleExtents(v, min, max, logarithmic);
lbajardsilogic@0 567
lbajardsilogic@0 568 float val = min + (float(h - y) * float(max - min)) / h;
lbajardsilogic@0 569
lbajardsilogic@0 570 if (logarithmic) {
lbajardsilogic@0 571 val = powf(10.f, val);
lbajardsilogic@0 572 }
lbajardsilogic@0 573
lbajardsilogic@0 574 if (shouldConvertMIDIToHz()) {
lbajardsilogic@0 575 val = Pitch::getPitchForFrequency(val);
lbajardsilogic@0 576 }
lbajardsilogic@0 577
lbajardsilogic@0 578 return val;
lbajardsilogic@0 579 }
lbajardsilogic@0 580
lbajardsilogic@0 581 void
lbajardsilogic@0 582 NoteLayer::paint(View *v, QPainter &paint, QRect rect) const
lbajardsilogic@0 583 {
lbajardsilogic@0 584 if (!m_model || !m_model->isOK()) return;
lbajardsilogic@0 585
lbajardsilogic@0 586 int sampleRate = m_model->getSampleRate();
lbajardsilogic@0 587 if (!sampleRate) return;
lbajardsilogic@0 588
lbajardsilogic@0 589 // Profiler profiler("NoteLayer::paint", true);
lbajardsilogic@0 590
lbajardsilogic@0 591 int x0 = rect.left(), x1 = rect.right();
lbajardsilogic@0 592 long frame0 = v->getFrameForX(x0);
lbajardsilogic@0 593 long frame1 = v->getFrameForX(x1);
lbajardsilogic@0 594
lbajardsilogic@0 595 NoteModel::PointList points(m_model->getPoints(frame0, frame1));
lbajardsilogic@0 596 if (points.empty()) return;
lbajardsilogic@0 597
lbajardsilogic@0 598 paint.setPen(m_colour);
lbajardsilogic@0 599
lbajardsilogic@0 600 QColor brushColour(m_colour);
lbajardsilogic@0 601 brushColour.setAlpha(80);
lbajardsilogic@0 602
lbajardsilogic@0 603 // std::cerr << "NoteLayer::paint: resolution is "
lbajardsilogic@0 604 // << m_model->getResolution() << " frames" << std::endl;
lbajardsilogic@0 605
lbajardsilogic@0 606 float min = m_model->getValueMinimum();
lbajardsilogic@0 607 float max = m_model->getValueMaximum();
lbajardsilogic@0 608 if (max == min) max = min + 1.0;
lbajardsilogic@0 609
lbajardsilogic@0 610 QPoint localPos;
lbajardsilogic@0 611 long illuminateFrame = -1;
lbajardsilogic@0 612
lbajardsilogic@0 613 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
lbajardsilogic@0 614 NoteModel::PointList localPoints =
lbajardsilogic@0 615 getLocalPoints(v, localPos.x());
lbajardsilogic@0 616 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
lbajardsilogic@0 617 }
lbajardsilogic@0 618
lbajardsilogic@0 619 paint.save();
lbajardsilogic@0 620 paint.setRenderHint(QPainter::Antialiasing, false);
lbajardsilogic@0 621
lbajardsilogic@0 622 for (NoteModel::PointList::const_iterator i = points.begin();
lbajardsilogic@0 623 i != points.end(); ++i) {
lbajardsilogic@0 624
lbajardsilogic@0 625 const NoteModel::Point &p(*i);
lbajardsilogic@0 626
lbajardsilogic@0 627 int x = v->getXForFrame(p.frame);
lbajardsilogic@0 628 int y = getYForValue(v, p.value);
lbajardsilogic@0 629 int w = v->getXForFrame(p.frame + p.duration) - x;
lbajardsilogic@0 630 int h = 3;
lbajardsilogic@0 631
lbajardsilogic@0 632 if (m_model->getValueQuantization() != 0.0) {
lbajardsilogic@0 633 h = y - getYForValue(v, p.value + m_model->getValueQuantization());
lbajardsilogic@0 634 if (h < 3) h = 3;
lbajardsilogic@0 635 }
lbajardsilogic@0 636
lbajardsilogic@0 637 if (w < 1) w = 1;
lbajardsilogic@0 638 paint.setPen(m_colour);
lbajardsilogic@0 639 paint.setBrush(brushColour);
lbajardsilogic@0 640
lbajardsilogic@0 641 if (illuminateFrame == p.frame) {
lbajardsilogic@0 642 if (localPos.y() >= y - h && localPos.y() < y) {
lbajardsilogic@0 643 paint.setPen(Qt::black);//!!!
lbajardsilogic@0 644 paint.setBrush(Qt::black);//!!!
lbajardsilogic@0 645 }
lbajardsilogic@0 646 }
lbajardsilogic@0 647
lbajardsilogic@0 648 paint.drawRect(x, y - h/2, w, h);
lbajardsilogic@0 649
lbajardsilogic@0 650 /// if (p.label != "") {
lbajardsilogic@0 651 /// paint.drawText(x + 5, y - paint.fontMetrics().height() + paint.fontMetrics().ascent(), p.label);
lbajardsilogic@0 652 /// }
lbajardsilogic@0 653 }
lbajardsilogic@0 654
lbajardsilogic@0 655 paint.restore();
lbajardsilogic@0 656 }
lbajardsilogic@0 657
lbajardsilogic@0 658 void
lbajardsilogic@0 659 NoteLayer::drawStart(View *v, QMouseEvent *e)
lbajardsilogic@0 660 {
lbajardsilogic@0 661 // std::cerr << "NoteLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 662
lbajardsilogic@0 663 if (!m_model) return;
lbajardsilogic@0 664
lbajardsilogic@0 665 long frame = v->getFrameForX(e->x());
lbajardsilogic@0 666 if (frame < 0) frame = 0;
lbajardsilogic@0 667 frame = frame / m_model->getResolution() * m_model->getResolution();
lbajardsilogic@0 668
lbajardsilogic@0 669 float value = getValueForY(v, e->y());
lbajardsilogic@0 670
lbajardsilogic@0 671 m_editingPoint = NoteModel::Point(frame, value, 0, tr("New Point"));
lbajardsilogic@0 672 m_originalPoint = m_editingPoint;
lbajardsilogic@0 673
lbajardsilogic@0 674 if (m_editingCommand) m_editingCommand->finish();
lbajardsilogic@0 675 m_editingCommand = new NoteModel::EditCommand(m_model,
lbajardsilogic@0 676 tr("Draw Point"));
lbajardsilogic@0 677 m_editingCommand->addPoint(m_editingPoint);
lbajardsilogic@0 678
lbajardsilogic@0 679 m_editing = true;
lbajardsilogic@0 680 }
lbajardsilogic@0 681
lbajardsilogic@0 682 void
lbajardsilogic@0 683 NoteLayer::drawDrag(View *v, QMouseEvent *e)
lbajardsilogic@0 684 {
lbajardsilogic@0 685 // std::cerr << "NoteLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 686
lbajardsilogic@0 687 if (!m_model || !m_editing) return;
lbajardsilogic@0 688
lbajardsilogic@0 689 long frame = v->getFrameForX(e->x());
lbajardsilogic@0 690 if (frame < 0) frame = 0;
lbajardsilogic@0 691 frame = frame / m_model->getResolution() * m_model->getResolution();
lbajardsilogic@0 692
lbajardsilogic@0 693 float newValue = getValueForY(v, e->y());
lbajardsilogic@0 694
lbajardsilogic@0 695 long newFrame = m_editingPoint.frame;
lbajardsilogic@0 696 long newDuration = frame - newFrame;
lbajardsilogic@0 697 if (newDuration < 0) {
lbajardsilogic@0 698 newFrame = frame;
lbajardsilogic@0 699 newDuration = -newDuration;
lbajardsilogic@0 700 } else if (newDuration == 0) {
lbajardsilogic@0 701 newDuration = 1;
lbajardsilogic@0 702 }
lbajardsilogic@0 703
lbajardsilogic@0 704 m_editingCommand->deletePoint(m_editingPoint);
lbajardsilogic@0 705 m_editingPoint.frame = newFrame;
lbajardsilogic@0 706 m_editingPoint.value = newValue;
lbajardsilogic@0 707 m_editingPoint.duration = newDuration;
lbajardsilogic@0 708 m_editingCommand->addPoint(m_editingPoint);
lbajardsilogic@0 709 }
lbajardsilogic@0 710
lbajardsilogic@0 711 void
lbajardsilogic@0 712 NoteLayer::drawEnd(View *, QMouseEvent *)
lbajardsilogic@0 713 {
lbajardsilogic@0 714 // std::cerr << "NoteLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 715 if (!m_model || !m_editing) return;
lbajardsilogic@0 716 m_editingCommand->finish();
lbajardsilogic@0 717 m_editingCommand = 0;
lbajardsilogic@0 718 m_editing = false;
lbajardsilogic@0 719 }
lbajardsilogic@0 720
lbajardsilogic@0 721 void
lbajardsilogic@0 722 NoteLayer::editStart(View *v, QMouseEvent *e)
lbajardsilogic@0 723 {
lbajardsilogic@0 724 // std::cerr << "NoteLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 725
lbajardsilogic@0 726 if (!m_model) return;
lbajardsilogic@0 727
lbajardsilogic@0 728 NoteModel::PointList points = getLocalPoints(v, e->x());
lbajardsilogic@0 729 if (points.empty()) return;
lbajardsilogic@0 730
lbajardsilogic@0 731 m_editingPoint = *points.begin();
lbajardsilogic@0 732 m_originalPoint = m_editingPoint;
lbajardsilogic@0 733
lbajardsilogic@0 734 if (m_editingCommand) {
lbajardsilogic@0 735 m_editingCommand->finish();
lbajardsilogic@0 736 m_editingCommand = 0;
lbajardsilogic@0 737 }
lbajardsilogic@0 738
lbajardsilogic@0 739 m_editing = true;
lbajardsilogic@0 740 }
lbajardsilogic@0 741
lbajardsilogic@0 742 void
lbajardsilogic@0 743 NoteLayer::editDrag(View *v, QMouseEvent *e)
lbajardsilogic@0 744 {
lbajardsilogic@0 745 // std::cerr << "NoteLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 746
lbajardsilogic@0 747 if (!m_model || !m_editing) return;
lbajardsilogic@0 748
lbajardsilogic@0 749 long frame = v->getFrameForX(e->x());
lbajardsilogic@0 750 if (frame < 0) frame = 0;
lbajardsilogic@0 751 frame = frame / m_model->getResolution() * m_model->getResolution();
lbajardsilogic@0 752
lbajardsilogic@0 753 float value = getValueForY(v, e->y());
lbajardsilogic@0 754
lbajardsilogic@0 755 if (!m_editingCommand) {
lbajardsilogic@0 756 m_editingCommand = new NoteModel::EditCommand(m_model,
lbajardsilogic@0 757 tr("Drag Point"));
lbajardsilogic@0 758 }
lbajardsilogic@0 759
lbajardsilogic@0 760 m_editingCommand->deletePoint(m_editingPoint);
lbajardsilogic@0 761 m_editingPoint.frame = frame;
lbajardsilogic@0 762 m_editingPoint.value = value;
lbajardsilogic@0 763 m_editingCommand->addPoint(m_editingPoint);
lbajardsilogic@0 764 }
lbajardsilogic@0 765
lbajardsilogic@0 766 void
lbajardsilogic@0 767 NoteLayer::editEnd(View *, QMouseEvent *)
lbajardsilogic@0 768 {
lbajardsilogic@0 769 // std::cerr << "NoteLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 770 if (!m_model || !m_editing) return;
lbajardsilogic@0 771
lbajardsilogic@0 772 if (m_editingCommand) {
lbajardsilogic@0 773
lbajardsilogic@0 774 QString newName = m_editingCommand->getName();
lbajardsilogic@0 775
lbajardsilogic@0 776 if (m_editingPoint.frame != m_originalPoint.frame) {
lbajardsilogic@0 777 if (m_editingPoint.value != m_originalPoint.value) {
lbajardsilogic@0 778 newName = tr("Edit Point");
lbajardsilogic@0 779 } else {
lbajardsilogic@0 780 newName = tr("Relocate Point");
lbajardsilogic@0 781 }
lbajardsilogic@0 782 } else {
lbajardsilogic@0 783 newName = tr("Change Point Value");
lbajardsilogic@0 784 }
lbajardsilogic@0 785
lbajardsilogic@0 786 m_editingCommand->setName(newName);
lbajardsilogic@0 787 m_editingCommand->finish();
lbajardsilogic@0 788 }
lbajardsilogic@0 789
lbajardsilogic@0 790 m_editingCommand = 0;
lbajardsilogic@0 791 m_editing = false;
lbajardsilogic@0 792 }
lbajardsilogic@0 793
lbajardsilogic@0 794 void
lbajardsilogic@0 795 NoteLayer::editOpen(View *v, QMouseEvent *e)
lbajardsilogic@0 796 {
lbajardsilogic@0 797 if (!m_model) return;
lbajardsilogic@0 798
lbajardsilogic@0 799 NoteModel::PointList points = getLocalPoints(v, e->x());
lbajardsilogic@0 800 if (points.empty()) return;
lbajardsilogic@0 801
lbajardsilogic@0 802 NoteModel::Point note = *points.begin();
lbajardsilogic@0 803
lbajardsilogic@0 804 ItemEditDialog *dialog = new ItemEditDialog
lbajardsilogic@0 805 (m_model->getSampleRate(),
lbajardsilogic@0 806 ItemEditDialog::ShowTime |
lbajardsilogic@0 807 ItemEditDialog::ShowDuration |
lbajardsilogic@0 808 ItemEditDialog::ShowValue |
lbajardsilogic@0 809 ItemEditDialog::ShowText,
lbajardsilogic@0 810 m_model->getScaleUnits());
lbajardsilogic@0 811
lbajardsilogic@0 812 dialog->setFrameTime(note.frame);
lbajardsilogic@0 813 dialog->setValue(note.value);
lbajardsilogic@0 814 dialog->setFrameDuration(note.duration);
lbajardsilogic@0 815 dialog->setText(note.label);
lbajardsilogic@0 816
lbajardsilogic@0 817 if (dialog->exec() == QDialog::Accepted) {
lbajardsilogic@0 818
lbajardsilogic@0 819 NoteModel::Point newNote = note;
lbajardsilogic@0 820 newNote.frame = dialog->getFrameTime();
lbajardsilogic@0 821 newNote.value = dialog->getValue();
lbajardsilogic@0 822 newNote.duration = dialog->getFrameDuration();
lbajardsilogic@0 823 newNote.label = dialog->getText();
lbajardsilogic@0 824
lbajardsilogic@0 825 NoteModel::EditCommand *command = new NoteModel::EditCommand
lbajardsilogic@0 826 (m_model, tr("Edit Point"));
lbajardsilogic@0 827 command->deletePoint(note);
lbajardsilogic@0 828 command->addPoint(newNote);
lbajardsilogic@0 829 command->finish();
lbajardsilogic@0 830 }
lbajardsilogic@0 831
lbajardsilogic@0 832 delete dialog;
lbajardsilogic@0 833 }
lbajardsilogic@0 834
lbajardsilogic@0 835 void
lbajardsilogic@0 836 NoteLayer::moveSelection(Selection s, size_t newStartFrame)
lbajardsilogic@0 837 {
lbajardsilogic@0 838 if (!m_model) return;
lbajardsilogic@0 839
lbajardsilogic@0 840 NoteModel::EditCommand *command =
lbajardsilogic@0 841 new NoteModel::EditCommand(m_model, tr("Drag Selection"));
lbajardsilogic@0 842
lbajardsilogic@0 843 NoteModel::PointList points =
lbajardsilogic@0 844 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 845
lbajardsilogic@0 846 for (NoteModel::PointList::iterator i = points.begin();
lbajardsilogic@0 847 i != points.end(); ++i) {
lbajardsilogic@0 848
lbajardsilogic@0 849 if (s.contains(i->frame)) {
lbajardsilogic@0 850 NoteModel::Point newPoint(*i);
lbajardsilogic@0 851 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
lbajardsilogic@0 852 command->deletePoint(*i);
lbajardsilogic@0 853 command->addPoint(newPoint);
lbajardsilogic@0 854 }
lbajardsilogic@0 855 }
lbajardsilogic@0 856
lbajardsilogic@0 857 command->finish();
lbajardsilogic@0 858 }
lbajardsilogic@0 859
lbajardsilogic@0 860 void
lbajardsilogic@0 861 NoteLayer::resizeSelection(Selection s, Selection newSize)
lbajardsilogic@0 862 {
lbajardsilogic@0 863 if (!m_model) return;
lbajardsilogic@0 864
lbajardsilogic@0 865 NoteModel::EditCommand *command =
lbajardsilogic@0 866 new NoteModel::EditCommand(m_model, tr("Resize Selection"));
lbajardsilogic@0 867
lbajardsilogic@0 868 NoteModel::PointList points =
lbajardsilogic@0 869 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 870
lbajardsilogic@0 871 double ratio =
lbajardsilogic@0 872 double(newSize.getEndFrame() - newSize.getStartFrame()) /
lbajardsilogic@0 873 double(s.getEndFrame() - s.getStartFrame());
lbajardsilogic@0 874
lbajardsilogic@0 875 for (NoteModel::PointList::iterator i = points.begin();
lbajardsilogic@0 876 i != points.end(); ++i) {
lbajardsilogic@0 877
lbajardsilogic@0 878 if (s.contains(i->frame)) {
lbajardsilogic@0 879
lbajardsilogic@0 880 double targetStart = i->frame;
lbajardsilogic@0 881 targetStart = newSize.getStartFrame() +
lbajardsilogic@0 882 double(targetStart - s.getStartFrame()) * ratio;
lbajardsilogic@0 883
lbajardsilogic@0 884 double targetEnd = i->frame + i->duration;
lbajardsilogic@0 885 targetEnd = newSize.getStartFrame() +
lbajardsilogic@0 886 double(targetEnd - s.getStartFrame()) * ratio;
lbajardsilogic@0 887
lbajardsilogic@0 888 NoteModel::Point newPoint(*i);
lbajardsilogic@0 889 newPoint.frame = lrint(targetStart);
lbajardsilogic@0 890 newPoint.duration = lrint(targetEnd - targetStart);
lbajardsilogic@0 891 command->deletePoint(*i);
lbajardsilogic@0 892 command->addPoint(newPoint);
lbajardsilogic@0 893 }
lbajardsilogic@0 894 }
lbajardsilogic@0 895
lbajardsilogic@0 896 command->finish();
lbajardsilogic@0 897 }
lbajardsilogic@0 898
lbajardsilogic@0 899 void
lbajardsilogic@0 900 NoteLayer::deleteSelection(Selection s)
lbajardsilogic@0 901 {
lbajardsilogic@0 902 if (!m_model) return;
lbajardsilogic@0 903
lbajardsilogic@0 904 NoteModel::EditCommand *command =
lbajardsilogic@0 905 new NoteModel::EditCommand(m_model, tr("Delete Selected Points"));
lbajardsilogic@0 906
lbajardsilogic@0 907 NoteModel::PointList points =
lbajardsilogic@0 908 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 909
lbajardsilogic@0 910 for (NoteModel::PointList::iterator i = points.begin();
lbajardsilogic@0 911 i != points.end(); ++i) {
lbajardsilogic@0 912
lbajardsilogic@0 913 if (s.contains(i->frame)) {
lbajardsilogic@0 914 command->deletePoint(*i);
lbajardsilogic@0 915 }
lbajardsilogic@0 916 }
lbajardsilogic@0 917
lbajardsilogic@0 918 command->finish();
lbajardsilogic@0 919 }
lbajardsilogic@0 920
lbajardsilogic@0 921 void
lbajardsilogic@0 922 NoteLayer::copy(Selection s, Clipboard &to)
lbajardsilogic@0 923 {
lbajardsilogic@0 924 if (!m_model) return;
lbajardsilogic@0 925
lbajardsilogic@0 926 NoteModel::PointList points =
lbajardsilogic@0 927 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 928
lbajardsilogic@0 929 for (NoteModel::PointList::iterator i = points.begin();
lbajardsilogic@0 930 i != points.end(); ++i) {
lbajardsilogic@0 931 if (s.contains(i->frame)) {
lbajardsilogic@0 932 Clipboard::Point point(i->frame, i->value, i->duration, i->label);
lbajardsilogic@0 933 to.addPoint(point);
lbajardsilogic@0 934 }
lbajardsilogic@0 935 }
lbajardsilogic@0 936 }
lbajardsilogic@0 937
lbajardsilogic@0 938 bool
lbajardsilogic@0 939 NoteLayer::paste(const Clipboard &from, int frameOffset, bool /* interactive */)
lbajardsilogic@0 940 {
lbajardsilogic@0 941 if (!m_model) return false;
lbajardsilogic@0 942
lbajardsilogic@0 943 const Clipboard::PointList &points = from.getPoints();
lbajardsilogic@0 944
lbajardsilogic@0 945 NoteModel::EditCommand *command =
lbajardsilogic@0 946 new NoteModel::EditCommand(m_model, tr("Paste"));
lbajardsilogic@0 947
lbajardsilogic@0 948 for (Clipboard::PointList::const_iterator i = points.begin();
lbajardsilogic@0 949 i != points.end(); ++i) {
lbajardsilogic@0 950
lbajardsilogic@0 951 if (!i->haveFrame()) continue;
lbajardsilogic@0 952 size_t frame = 0;
lbajardsilogic@0 953 if (frameOffset > 0 || -frameOffset < i->getFrame()) {
lbajardsilogic@0 954 frame = i->getFrame() + frameOffset;
lbajardsilogic@0 955 }
lbajardsilogic@0 956 NoteModel::Point newPoint(frame);
lbajardsilogic@0 957
lbajardsilogic@0 958 if (i->haveLabel()) newPoint.label = i->getLabel();
lbajardsilogic@0 959 if (i->haveValue()) newPoint.value = i->getValue();
lbajardsilogic@0 960 else newPoint.value = (m_model->getValueMinimum() +
lbajardsilogic@0 961 m_model->getValueMaximum()) / 2;
lbajardsilogic@0 962 if (i->haveDuration()) newPoint.duration = i->getDuration();
lbajardsilogic@0 963 else {
lbajardsilogic@0 964 size_t nextFrame = frame;
lbajardsilogic@0 965 Clipboard::PointList::const_iterator j = i;
lbajardsilogic@0 966 for (; j != points.end(); ++j) {
lbajardsilogic@0 967 if (!j->haveFrame()) continue;
lbajardsilogic@0 968 if (j != i) break;
lbajardsilogic@0 969 }
lbajardsilogic@0 970 if (j != points.end()) {
lbajardsilogic@0 971 nextFrame = j->getFrame();
lbajardsilogic@0 972 }
lbajardsilogic@0 973 if (nextFrame == frame) {
lbajardsilogic@0 974 newPoint.duration = m_model->getResolution();
lbajardsilogic@0 975 } else {
lbajardsilogic@0 976 newPoint.duration = nextFrame - frame;
lbajardsilogic@0 977 }
lbajardsilogic@0 978 }
lbajardsilogic@0 979
lbajardsilogic@0 980 command->addPoint(newPoint);
lbajardsilogic@0 981 }
lbajardsilogic@0 982
lbajardsilogic@0 983 command->finish();
lbajardsilogic@0 984 return true;
lbajardsilogic@0 985 }
lbajardsilogic@0 986
lbajardsilogic@0 987 QString
lbajardsilogic@0 988 NoteLayer::toXmlString(QString indent, QString extraAttributes) const
lbajardsilogic@0 989 {
lbajardsilogic@0 990 return Layer::toXmlString(indent, extraAttributes +
lbajardsilogic@0 991 QString(" colour=\"%1\" verticalScale=\"%2\"")
lbajardsilogic@0 992 .arg(encodeColour(m_colour)).arg(m_verticalScale));
lbajardsilogic@0 993 }
lbajardsilogic@0 994
lbajardsilogic@18 995 QString
lbajardsilogic@18 996 NoteLayer::toEasaierXmlString(QString indent, QString extraAttributes) const
lbajardsilogic@18 997 {
lbajardsilogic@18 998 return Layer::toEasaierXmlString(indent, extraAttributes +
lbajardsilogic@18 999 QString(" colour=\"%1\" verticalScale=\"%2\"")
lbajardsilogic@18 1000 .arg(encodeColour(m_colour)).arg(m_verticalScale));
lbajardsilogic@18 1001 }
lbajardsilogic@18 1002
lbajardsilogic@0 1003 void
lbajardsilogic@0 1004 NoteLayer::setProperties(const QXmlAttributes &attributes)
lbajardsilogic@0 1005 {
lbajardsilogic@0 1006 QString colourSpec = attributes.value("colour");
lbajardsilogic@0 1007 if (colourSpec != "") {
lbajardsilogic@0 1008 QColor colour(colourSpec);
lbajardsilogic@0 1009 if (colour.isValid()) {
lbajardsilogic@0 1010 setBaseColour(QColor(colourSpec));
lbajardsilogic@0 1011 }
lbajardsilogic@0 1012 }
lbajardsilogic@0 1013
lbajardsilogic@0 1014 bool ok;
lbajardsilogic@0 1015 VerticalScale scale = (VerticalScale)
lbajardsilogic@0 1016 attributes.value("verticalScale").toInt(&ok);
lbajardsilogic@0 1017 if (ok) setVerticalScale(scale);
lbajardsilogic@0 1018 }
lbajardsilogic@0 1019
lbajardsilogic@0 1020