comparison layer/NoteLayer.cpp @ 44:ad214997dddb

* Refactor Layer classes so as no longer to store a single View pointer; instead they need to be able to draw themselves on any View on demand. Layers with caches (e.g. spectrogram) will need to be further refactored so as to maintain a per-View cache * Begin refactoring MainWindow by pulling out the document stuff (set of layers, models etc) into a Document class. Not yet in use. This revision is fairly unstable.
author Chris Cannam
date Thu, 02 Mar 2006 16:58:49 +0000
parents 78515b1e29eb
children 01ab51f72e84
comparison
equal deleted inserted replaced
43:78515b1e29eb 44:ad214997dddb
24 #include <QMouseEvent> 24 #include <QMouseEvent>
25 25
26 #include <iostream> 26 #include <iostream>
27 #include <cmath> 27 #include <cmath>
28 28
29 NoteLayer::NoteLayer(View *w) : 29 NoteLayer::NoteLayer() :
30 Layer(w), 30 Layer(),
31 m_model(0), 31 m_model(0),
32 m_editing(false), 32 m_editing(false),
33 m_originalPoint(0, 0.0, 0, tr("New Point")), 33 m_originalPoint(0, 0.0, 0, tr("New Point")),
34 m_editingPoint(0, 0.0, 0, tr("New Point")), 34 m_editingPoint(0, 0.0, 0, tr("New Point")),
35 m_editingCommand(0), 35 m_editingCommand(0),
36 m_colour(Qt::black), 36 m_colour(Qt::black),
37 m_verticalScale(MinMaxRangeScale) 37 m_verticalScale(MinMaxRangeScale)
38 { 38 {
39 m_view->addLayer(this); 39
40 } 40 }
41 41
42 void 42 void
43 NoteLayer::setModel(NoteModel *model) 43 NoteLayer::setModel(NoteModel *model)
44 { 44 {
165 m_verticalScale = scale; 165 m_verticalScale = scale;
166 emit layerParametersChanged(); 166 emit layerParametersChanged();
167 } 167 }
168 168
169 bool 169 bool
170 NoteLayer::isLayerScrollable() const 170 NoteLayer::isLayerScrollable(const View *v) const
171 { 171 {
172 QPoint discard; 172 QPoint discard;
173 return !m_view->shouldIlluminateLocalFeatures(this, discard); 173 return !v->shouldIlluminateLocalFeatures(this, discard);
174 } 174 }
175 175
176 NoteModel::PointList 176 NoteModel::PointList
177 NoteLayer::getLocalPoints(int x) const 177 NoteLayer::getLocalPoints(View *v, int x) const
178 { 178 {
179 if (!m_model) return NoteModel::PointList(); 179 if (!m_model) return NoteModel::PointList();
180 180
181 long frame = getFrameForX(x); 181 long frame = v->getFrameForX(x);
182 182
183 NoteModel::PointList onPoints = 183 NoteModel::PointList onPoints =
184 m_model->getPoints(frame); 184 m_model->getPoints(frame);
185 185
186 if (!onPoints.empty()) { 186 if (!onPoints.empty()) {
194 194
195 NoteModel::PointList usePoints = prevPoints; 195 NoteModel::PointList usePoints = prevPoints;
196 196
197 if (prevPoints.empty()) { 197 if (prevPoints.empty()) {
198 usePoints = nextPoints; 198 usePoints = nextPoints;
199 } else if (prevPoints.begin()->frame < m_view->getStartFrame() && 199 } else if (prevPoints.begin()->frame < v->getStartFrame() &&
200 !(nextPoints.begin()->frame > m_view->getEndFrame())) { 200 !(nextPoints.begin()->frame > v->getEndFrame())) {
201 usePoints = nextPoints; 201 usePoints = nextPoints;
202 } else if (nextPoints.begin()->frame - frame < 202 } else if (nextPoints.begin()->frame - frame <
203 frame - prevPoints.begin()->frame) { 203 frame - prevPoints.begin()->frame) {
204 usePoints = nextPoints; 204 usePoints = nextPoints;
205 } 205 }
206 206
207 if (!usePoints.empty()) { 207 if (!usePoints.empty()) {
208 int fuzz = 2; 208 int fuzz = 2;
209 int px = getXForFrame(usePoints.begin()->frame); 209 int px = v->getXForFrame(usePoints.begin()->frame);
210 if ((px > x && px - x > fuzz) || 210 if ((px > x && px - x > fuzz) ||
211 (px < x && x - px > fuzz + 1)) { 211 (px < x && x - px > fuzz + 1)) {
212 usePoints.clear(); 212 usePoints.clear();
213 } 213 }
214 } 214 }
215 215
216 return usePoints; 216 return usePoints;
217 } 217 }
218 218
219 QString 219 QString
220 NoteLayer::getFeatureDescription(QPoint &pos) const 220 NoteLayer::getFeatureDescription(View *v, QPoint &pos) const
221 { 221 {
222 int x = pos.x(); 222 int x = pos.x();
223 223
224 if (!m_model || !m_model->getSampleRate()) return ""; 224 if (!m_model || !m_model->getSampleRate()) return "";
225 225
226 NoteModel::PointList points = getLocalPoints(x); 226 NoteModel::PointList points = getLocalPoints(v, x);
227 227
228 if (points.empty()) { 228 if (points.empty()) {
229 if (!m_model->isReady()) { 229 if (!m_model->isReady()) {
230 return tr("In progress"); 230 return tr("In progress");
231 } else { 231 } else {
236 Note note(0); 236 Note note(0);
237 NoteModel::PointList::iterator i; 237 NoteModel::PointList::iterator i;
238 238
239 for (i = points.begin(); i != points.end(); ++i) { 239 for (i = points.begin(); i != points.end(); ++i) {
240 240
241 int y = getYForValue(i->value); 241 int y = getYForValue(v, i->value);
242 int h = 3; 242 int h = 3;
243 243
244 if (m_model->getValueQuantization() != 0.0) { 244 if (m_model->getValueQuantization() != 0.0) {
245 h = y - getYForValue(i->value + m_model->getValueQuantization()); 245 h = y - getYForValue(v, i->value + m_model->getValueQuantization());
246 if (h < 3) h = 3; 246 if (h < 3) h = 3;
247 } 247 }
248 248
249 if (pos.y() >= y - h && pos.y() <= y) { 249 if (pos.y() >= y - h && pos.y() <= y) {
250 note = *i; 250 note = *i;
272 .arg(note.value) 272 .arg(note.value)
273 .arg(rd.toText(true).c_str()) 273 .arg(rd.toText(true).c_str())
274 .arg(note.label); 274 .arg(note.label);
275 } 275 }
276 276
277 pos = QPoint(getXForFrame(note.frame), 277 pos = QPoint(v->getXForFrame(note.frame),
278 getYForValue(note.value)); 278 getYForValue(v, note.value));
279 return text; 279 return text;
280 } 280 }
281 281
282 bool 282 bool
283 NoteLayer::snapToFeatureFrame(int &frame, 283 NoteLayer::snapToFeatureFrame(View *v, int &frame,
284 size_t &resolution, 284 size_t &resolution,
285 SnapType snap) const 285 SnapType snap) const
286 { 286 {
287 if (!m_model) { 287 if (!m_model) {
288 return Layer::snapToFeatureFrame(frame, resolution, snap); 288 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
289 } 289 }
290 290
291 resolution = m_model->getResolution(); 291 resolution = m_model->getResolution();
292 NoteModel::PointList points; 292 NoteModel::PointList points;
293 293
294 if (snap == SnapNeighbouring) { 294 if (snap == SnapNeighbouring) {
295 295
296 points = getLocalPoints(getXForFrame(frame)); 296 points = getLocalPoints(v, v->getXForFrame(frame));
297 if (points.empty()) return false; 297 if (points.empty()) return false;
298 frame = points.begin()->frame; 298 frame = points.begin()->frame;
299 return true; 299 return true;
300 } 300 }
301 301
350 frame = snapped; 350 frame = snapped;
351 return found; 351 return found;
352 } 352 }
353 353
354 int 354 int
355 NoteLayer::getYForValue(float value) const 355 NoteLayer::getYForValue(View *v, float value) const
356 { 356 {
357 float min, max, h = m_view->height(); 357 float min, max, h = v->height();
358 358
359 switch (m_verticalScale) { 359 switch (m_verticalScale) {
360 360
361 case MIDIRangeScale: 361 case MIDIRangeScale:
362 min = 0.0; 362 min = 0.0;
373 value = Pitch::getFrequencyForPitch(lrintf(value), 373 value = Pitch::getFrequencyForPitch(lrintf(value),
374 value - lrintf(value)); 374 value - lrintf(value));
375 375
376 // If we have a spectrogram layer on the same view as us, align 376 // If we have a spectrogram layer on the same view as us, align
377 // ourselves with it... 377 // ourselves with it...
378 for (int i = 0; i < m_view->getLayerCount(); ++i) { 378 for (int i = 0; i < v->getLayerCount(); ++i) {
379 SpectrogramLayer *spectrogram = dynamic_cast<SpectrogramLayer *> 379 SpectrogramLayer *spectrogram = dynamic_cast<SpectrogramLayer *>
380 (m_view->getLayer(i)); 380 (v->getLayer(i));
381 if (spectrogram) { 381 if (spectrogram) {
382 return spectrogram->getYForFrequency(value); 382 return spectrogram->getYForFrequency(v, value);
383 } 383 }
384 } 384 }
385 385
386 // ...otherwise just interpolate 386 // ...otherwise just interpolate
387 std::cerr << "FrequencyScale: value in = " << value << std::endl; 387 std::cerr << "FrequencyScale: value in = " << value << std::endl;
398 398
399 return int(h - ((value - min) * h) / (max - min)) - 1; 399 return int(h - ((value - min) * h) / (max - min)) - 1;
400 } 400 }
401 401
402 float 402 float
403 NoteLayer::getValueForY(int y) const 403 NoteLayer::getValueForY(View *v, int y) const
404 { 404 {
405 float min = m_model->getValueMinimum(); 405 float min = m_model->getValueMinimum();
406 float max = m_model->getValueMaximum(); 406 float max = m_model->getValueMaximum();
407 if (max == min) max = min + 1.0; 407 if (max == min) max = min + 1.0;
408 408
409 int h = m_view->height(); 409 int h = v->height();
410 410
411 return min + (float(h - y) * float(max - min)) / h; 411 return min + (float(h - y) * float(max - min)) / h;
412 } 412 }
413 413
414 void 414 void
415 NoteLayer::paint(QPainter &paint, QRect rect) const 415 NoteLayer::paint(View *v, QPainter &paint, QRect rect) const
416 { 416 {
417 if (!m_model || !m_model->isOK()) return; 417 if (!m_model || !m_model->isOK()) return;
418 418
419 int sampleRate = m_model->getSampleRate(); 419 int sampleRate = m_model->getSampleRate();
420 if (!sampleRate) return; 420 if (!sampleRate) return;
421 421
422 // Profiler profiler("NoteLayer::paint", true); 422 // Profiler profiler("NoteLayer::paint", true);
423 423
424 int x0 = rect.left(), x1 = rect.right(); 424 int x0 = rect.left(), x1 = rect.right();
425 long frame0 = getFrameForX(x0); 425 long frame0 = v->getFrameForX(x0);
426 long frame1 = getFrameForX(x1); 426 long frame1 = v->getFrameForX(x1);
427 427
428 NoteModel::PointList points(m_model->getPoints(frame0, frame1)); 428 NoteModel::PointList points(m_model->getPoints(frame0, frame1));
429 if (points.empty()) return; 429 if (points.empty()) return;
430 430
431 paint.setPen(m_colour); 431 paint.setPen(m_colour);
438 438
439 float min = m_model->getValueMinimum(); 439 float min = m_model->getValueMinimum();
440 float max = m_model->getValueMaximum(); 440 float max = m_model->getValueMaximum();
441 if (max == min) max = min + 1.0; 441 if (max == min) max = min + 1.0;
442 442
443 int origin = int(nearbyint(m_view->height() - 443 int origin = int(nearbyint(v->height() -
444 (-min * m_view->height()) / (max - min))); 444 (-min * v->height()) / (max - min)));
445 445
446 QPoint localPos; 446 QPoint localPos;
447 long illuminateFrame = -1; 447 long illuminateFrame = -1;
448 448
449 if (m_view->shouldIlluminateLocalFeatures(this, localPos)) { 449 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
450 NoteModel::PointList localPoints = 450 NoteModel::PointList localPoints =
451 getLocalPoints(localPos.x()); 451 getLocalPoints(v, localPos.x());
452 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame; 452 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
453 } 453 }
454 454
455 paint.save(); 455 paint.save();
456 paint.setRenderHint(QPainter::Antialiasing, false); 456 paint.setRenderHint(QPainter::Antialiasing, false);
458 for (NoteModel::PointList::const_iterator i = points.begin(); 458 for (NoteModel::PointList::const_iterator i = points.begin();
459 i != points.end(); ++i) { 459 i != points.end(); ++i) {
460 460
461 const NoteModel::Point &p(*i); 461 const NoteModel::Point &p(*i);
462 462
463 int x = getXForFrame(p.frame); 463 int x = v->getXForFrame(p.frame);
464 int y = getYForValue(p.value); 464 int y = getYForValue(v, p.value);
465 int w = getXForFrame(p.frame + p.duration) - x; 465 int w = v->getXForFrame(p.frame + p.duration) - x;
466 int h = 3; 466 int h = 3;
467 467
468 if (m_model->getValueQuantization() != 0.0) { 468 if (m_model->getValueQuantization() != 0.0) {
469 h = y - getYForValue(p.value + m_model->getValueQuantization()); 469 h = y - getYForValue(v, p.value + m_model->getValueQuantization());
470 if (h < 3) h = 3; 470 if (h < 3) h = 3;
471 } 471 }
472 472
473 if (w < 1) w = 1; 473 if (w < 1) w = 1;
474 paint.setPen(m_colour); 474 paint.setPen(m_colour);
490 490
491 paint.restore(); 491 paint.restore();
492 } 492 }
493 493
494 void 494 void
495 NoteLayer::drawStart(QMouseEvent *e) 495 NoteLayer::drawStart(View *v, QMouseEvent *e)
496 { 496 {
497 std::cerr << "NoteLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl; 497 std::cerr << "NoteLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl;
498 498
499 if (!m_model) return; 499 if (!m_model) return;
500 500
501 long frame = getFrameForX(e->x()); 501 long frame = v->getFrameForX(e->x());
502 if (frame < 0) frame = 0; 502 if (frame < 0) frame = 0;
503 frame = frame / m_model->getResolution() * m_model->getResolution(); 503 frame = frame / m_model->getResolution() * m_model->getResolution();
504 504
505 float value = getValueForY(e->y()); 505 float value = getValueForY(v, e->y());
506 506
507 m_editingPoint = NoteModel::Point(frame, value, 0, tr("New Point")); 507 m_editingPoint = NoteModel::Point(frame, value, 0, tr("New Point"));
508 m_originalPoint = m_editingPoint; 508 m_originalPoint = m_editingPoint;
509 509
510 if (m_editingCommand) m_editingCommand->finish(); 510 if (m_editingCommand) m_editingCommand->finish();
514 514
515 m_editing = true; 515 m_editing = true;
516 } 516 }
517 517
518 void 518 void
519 NoteLayer::drawDrag(QMouseEvent *e) 519 NoteLayer::drawDrag(View *v, QMouseEvent *e)
520 { 520 {
521 std::cerr << "NoteLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl; 521 std::cerr << "NoteLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl;
522 522
523 if (!m_model || !m_editing) return; 523 if (!m_model || !m_editing) return;
524 524
525 long frame = getFrameForX(e->x()); 525 long frame = v->getFrameForX(e->x());
526 if (frame < 0) frame = 0; 526 if (frame < 0) frame = 0;
527 frame = frame / m_model->getResolution() * m_model->getResolution(); 527 frame = frame / m_model->getResolution() * m_model->getResolution();
528 528
529 float value = getValueForY(e->y()); 529 float value = getValueForY(v, e->y());
530 530
531 m_editingCommand->deletePoint(m_editingPoint); 531 m_editingCommand->deletePoint(m_editingPoint);
532 m_editingPoint.frame = frame; 532 m_editingPoint.frame = frame;
533 m_editingPoint.value = value; 533 m_editingPoint.value = value;
534 m_editingCommand->addPoint(m_editingPoint); 534 m_editingCommand->addPoint(m_editingPoint);
535 } 535 }
536 536
537 void 537 void
538 NoteLayer::drawEnd(QMouseEvent *e) 538 NoteLayer::drawEnd(View *v, QMouseEvent *e)
539 { 539 {
540 std::cerr << "NoteLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl; 540 std::cerr << "NoteLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl;
541 if (!m_model || !m_editing) return; 541 if (!m_model || !m_editing) return;
542 m_editingCommand->finish(); 542 m_editingCommand->finish();
543 m_editingCommand = 0; 543 m_editingCommand = 0;
544 m_editing = false; 544 m_editing = false;
545 } 545 }
546 546
547 void 547 void
548 NoteLayer::editStart(QMouseEvent *e) 548 NoteLayer::editStart(View *v, QMouseEvent *e)
549 { 549 {
550 std::cerr << "NoteLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl; 550 std::cerr << "NoteLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
551 551
552 if (!m_model) return; 552 if (!m_model) return;
553 553
554 NoteModel::PointList points = getLocalPoints(e->x()); 554 NoteModel::PointList points = getLocalPoints(v, e->x());
555 if (points.empty()) return; 555 if (points.empty()) return;
556 556
557 m_editingPoint = *points.begin(); 557 m_editingPoint = *points.begin();
558 m_originalPoint = m_editingPoint; 558 m_originalPoint = m_editingPoint;
559 559
564 564
565 m_editing = true; 565 m_editing = true;
566 } 566 }
567 567
568 void 568 void
569 NoteLayer::editDrag(QMouseEvent *e) 569 NoteLayer::editDrag(View *v, QMouseEvent *e)
570 { 570 {
571 std::cerr << "NoteLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl; 571 std::cerr << "NoteLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl;
572 572
573 if (!m_model || !m_editing) return; 573 if (!m_model || !m_editing) return;
574 574
575 long frame = getFrameForX(e->x()); 575 long frame = v->getFrameForX(e->x());
576 if (frame < 0) frame = 0; 576 if (frame < 0) frame = 0;
577 frame = frame / m_model->getResolution() * m_model->getResolution(); 577 frame = frame / m_model->getResolution() * m_model->getResolution();
578 578
579 float value = getValueForY(e->y()); 579 float value = getValueForY(v, e->y());
580 580
581 if (!m_editingCommand) { 581 if (!m_editingCommand) {
582 m_editingCommand = new NoteModel::EditCommand(m_model, 582 m_editingCommand = new NoteModel::EditCommand(m_model,
583 tr("Drag Point")); 583 tr("Drag Point"));
584 } 584 }
588 m_editingPoint.value = value; 588 m_editingPoint.value = value;
589 m_editingCommand->addPoint(m_editingPoint); 589 m_editingCommand->addPoint(m_editingPoint);
590 } 590 }
591 591
592 void 592 void
593 NoteLayer::editEnd(QMouseEvent *e) 593 NoteLayer::editEnd(View *v, QMouseEvent *e)
594 { 594 {
595 std::cerr << "NoteLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl; 595 std::cerr << "NoteLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
596 if (!m_model || !m_editing) return; 596 if (!m_model || !m_editing) return;
597 597
598 if (m_editingCommand) { 598 if (m_editingCommand) {