Mercurial > hg > svgui
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) { |