comparison layer/NoteLayer.cpp @ 439:681542f0c8c5

* Add vertical zoom/pan to note layer as well (when not in auto-align or MIDI scale modes)
author Chris Cannam
date Fri, 24 Oct 2008 16:43:59 +0000
parents e1a9e478b7f2
children 4a14499fb184
comparison
equal deleted inserted replaced
438:76cd1c89eb06 439:681542f0c8c5
18 #include "data/model/Model.h" 18 #include "data/model/Model.h"
19 #include "base/RealTime.h" 19 #include "base/RealTime.h"
20 #include "base/Profiler.h" 20 #include "base/Profiler.h"
21 #include "base/Pitch.h" 21 #include "base/Pitch.h"
22 #include "base/LogRange.h" 22 #include "base/LogRange.h"
23 #include "base/RangeMapper.h"
23 #include "ColourDatabase.h" 24 #include "ColourDatabase.h"
24 #include "view/View.h" 25 #include "view/View.h"
25 26
26 #include "data/model/NoteModel.h" 27 #include "data/model/NoteModel.h"
27 28
43 m_model(0), 44 m_model(0),
44 m_editing(false), 45 m_editing(false),
45 m_originalPoint(0, 0.0, 0, 1.f, tr("New Point")), 46 m_originalPoint(0, 0.0, 0, 1.f, tr("New Point")),
46 m_editingPoint(0, 0.0, 0, 1.f, tr("New Point")), 47 m_editingPoint(0, 0.0, 0, 1.f, tr("New Point")),
47 m_editingCommand(0), 48 m_editingCommand(0),
48 m_verticalScale(AutoAlignScale) 49 m_verticalScale(AutoAlignScale),
50 m_scaleMinimum(0),
51 m_scaleMaximum(0)
49 { 52 {
50 53
51 } 54 }
52 55
53 void 56 void
57 m_model = model; 60 m_model = model;
58 61
59 connectSignals(m_model); 62 connectSignals(m_model);
60 63
61 // std::cerr << "NoteLayer::setModel(" << model << ")" << std::endl; 64 // std::cerr << "NoteLayer::setModel(" << model << ")" << std::endl;
65
66 m_scaleMinimum = 0;
67 m_scaleMaximum = 0;
62 68
63 emit modelReplaced(); 69 emit modelReplaced();
64 } 70 }
65 71
66 Layer::PropertyList 72 Layer::PropertyList
206 } 212 }
207 213
208 bool 214 bool
209 NoteLayer::getDisplayExtents(float &min, float &max) const 215 NoteLayer::getDisplayExtents(float &min, float &max) const
210 { 216 {
211 if (!m_model || m_verticalScale == AutoAlignScale) return false; 217 if (!m_model || shouldAutoAlign()) return false;
212 218
213 if (m_verticalScale == MIDIRangeScale) { 219 if (m_verticalScale == MIDIRangeScale) {
214 min = Pitch::getFrequencyForPitch(0); 220 min = Pitch::getFrequencyForPitch(0);
215 max = Pitch::getFrequencyForPitch(127); 221 max = Pitch::getFrequencyForPitch(127);
216 return true; 222 return true;
217 } 223 }
218 224
219 min = m_model->getValueMinimum(); 225 if (m_scaleMinimum == m_scaleMaximum) {
220 max = m_model->getValueMaximum(); 226 m_scaleMinimum = m_model->getValueMinimum();
227 m_scaleMaximum = m_model->getValueMaximum();
228 }
229
230 min = m_scaleMinimum;
231 max = m_scaleMaximum;
221 232
222 if (shouldConvertMIDIToHz()) { 233 if (shouldConvertMIDIToHz()) {
223 min = Pitch::getFrequencyForPitch(lrintf(min)); 234 min = Pitch::getFrequencyForPitch(lrintf(min));
224 max = Pitch::getFrequencyForPitch(lrintf(max + 1)); 235 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
225 } 236 }
226 237
227 return true; 238 return true;
239 }
240
241 bool
242 NoteLayer::setDisplayExtents(float min, float max)
243 {
244 if (!m_model) return false;
245
246 if (min == max) {
247 if (min == 0.f) {
248 max = 1.f;
249 } else {
250 max = min * 1.0001;
251 }
252 }
253
254 m_scaleMinimum = min;
255 m_scaleMaximum = max;
256
257 // std::cerr << "NoteLayer::setDisplayExtents: min = " << min << ", max = " << max << std::endl;
258
259 emit layerParametersChanged();
260 return true;
261 }
262
263 int
264 NoteLayer::getVerticalZoomSteps(int &defaultStep) const
265 {
266 if (shouldAutoAlign()) return 0;
267 if (!m_model) return 0;
268
269 defaultStep = 0;
270 return 100;
271 }
272
273 int
274 NoteLayer::getCurrentVerticalZoomStep() const
275 {
276 if (shouldAutoAlign()) return 0;
277 if (!m_model) return 0;
278
279 RangeMapper *mapper = getNewVerticalZoomRangeMapper();
280 if (!mapper) return 0;
281
282 float dmin, dmax;
283 getDisplayExtents(dmin, dmax);
284
285 int nr = mapper->getPositionForValue(dmax - dmin);
286
287 delete mapper;
288
289 return 100 - nr;
290 }
291
292 //!!! lots of duplication with TimeValueLayer
293
294 void
295 NoteLayer::setVerticalZoomStep(int step)
296 {
297 if (shouldAutoAlign()) return;
298 if (!m_model) return;
299
300 RangeMapper *mapper = getNewVerticalZoomRangeMapper();
301 if (!mapper) return;
302
303 float min, max;
304 bool logarithmic;
305 QString unit;
306 getValueExtents(min, max, logarithmic, unit);
307
308 float dmin, dmax;
309 getDisplayExtents(dmin, dmax);
310
311 float newdist = mapper->getValueForPosition(100 - step);
312
313 float newmin, newmax;
314
315 if (logarithmic) {
316
317 // see SpectrogramLayer::setVerticalZoomStep
318
319 newmax = (newdist + sqrtf(newdist*newdist + 4*dmin*dmax)) / 2;
320 newmin = newmax - newdist;
321
322 // std::cerr << "newmin = " << newmin << ", newmax = " << newmax << std::endl;
323
324 } else {
325 float dmid = (dmax + dmin) / 2;
326 newmin = dmid - newdist / 2;
327 newmax = dmid + newdist / 2;
328 }
329
330 if (newmin < min) {
331 newmax += (min - newmin);
332 newmin = min;
333 }
334 if (newmax > max) {
335 newmax = max;
336 }
337
338 std::cerr << "NoteLayer::setVerticalZoomStep: " << step << ": " << newmin << " -> " << newmax << " (range " << newdist << ")" << std::endl;
339
340 setDisplayExtents(newmin, newmax);
341 }
342
343 RangeMapper *
344 NoteLayer::getNewVerticalZoomRangeMapper() const
345 {
346 if (!m_model) return 0;
347
348 RangeMapper *mapper;
349
350 float min, max;
351 bool logarithmic;
352 QString unit;
353 getValueExtents(min, max, logarithmic, unit);
354
355 if (min == max) return 0;
356
357 if (logarithmic) {
358 mapper = new LogRangeMapper(0, 100, min, max, unit);
359 } else {
360 mapper = new LinearRangeMapper(0, 100, min, max, unit);
361 }
362
363 return mapper;
228 } 364 }
229 365
230 NoteModel::PointList 366 NoteModel::PointList
231 NoteLayer::getLocalPoints(View *v, int x) const 367 NoteLayer::getLocalPoints(View *v, int x) const
232 { 368 {
435 571
436 QString queryUnits; 572 QString queryUnits;
437 if (shouldConvertMIDIToHz()) queryUnits = "Hz"; 573 if (shouldConvertMIDIToHz()) queryUnits = "Hz";
438 else queryUnits = m_model->getScaleUnits(); 574 else queryUnits = m_model->getScaleUnits();
439 575
440 if (m_verticalScale == AutoAlignScale) { 576 if (shouldAutoAlign()) {
441 577
442 if (!v->getValueExtents(queryUnits, min, max, log)) { 578 if (!v->getValueExtents(queryUnits, min, max, log)) {
443 579
444 min = m_model->getValueMinimum(); 580 min = m_model->getValueMinimum();
445 max = m_model->getValueMaximum(); 581 max = m_model->getValueMaximum();
459 595
460 } 596 }
461 597
462 } else { 598 } else {
463 599
464 min = m_model->getValueMinimum(); 600 getDisplayExtents(min, max);
465 max = m_model->getValueMaximum();
466 601
467 if (m_verticalScale == MIDIRangeScale) { 602 if (m_verticalScale == MIDIRangeScale) {
468 min = Pitch::getFrequencyForPitch(0); 603 min = Pitch::getFrequencyForPitch(0);
469 max = Pitch::getFrequencyForPitch(127); 604 max = Pitch::getFrequencyForPitch(127);
470 } else if (shouldConvertMIDIToHz()) { 605 } else if (shouldConvertMIDIToHz()) {
526 if (shouldConvertMIDIToHz()) { 661 if (shouldConvertMIDIToHz()) {
527 val = Pitch::getPitchForFrequency(val); 662 val = Pitch::getPitchForFrequency(val);
528 } 663 }
529 664
530 return val; 665 return val;
666 }
667
668 bool
669 NoteLayer::shouldAutoAlign() const
670 {
671 if (!m_model) return false;
672 return (m_verticalScale == AutoAlignScale);
531 } 673 }
532 674
533 void 675 void
534 NoteLayer::paint(View *v, QPainter &paint, QRect rect) const 676 NoteLayer::paint(View *v, QPainter &paint, QRect rect) const
535 { 677 {