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