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