summaryrefslogtreecommitdiff
path: root/svgui/layer/NoteLayer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'svgui/layer/NoteLayer.cpp')
-rw-r--r--svgui/layer/NoteLayer.cpp239
1 files changed, 129 insertions, 110 deletions
diff --git a/svgui/layer/NoteLayer.cpp b/svgui/layer/NoteLayer.cpp
index db62868..38dbdb7 100644
--- a/svgui/layer/NoteLayer.cpp
+++ b/svgui/layer/NoteLayer.cpp
@@ -48,6 +48,7 @@
NoteLayer::NoteLayer() :
SingleColourLayer(),
+ m_modelUsesHz(true),
m_editing(false),
m_dragPointX(0),
m_dragPointY(0),
@@ -86,6 +87,9 @@ NoteLayer::setModel(ModelId modelId)
if (newModel) {
connectSignals(m_model);
+
+ QString unit = newModel->getScaleUnits();
+ m_modelUsesHz = (unit.toLower() == "hz");
}
m_scaleMinimum = 0;
@@ -131,9 +135,7 @@ NoteLayer::getPropertyGroupName(const PropertyName &name) const
QString
NoteLayer::getScaleUnits() const
{
- auto model = ModelById::getAs<NoteModel>(m_model);
- if (model) return model->getScaleUnits();
- else return "";
+ return "Hz";
}
int
@@ -191,8 +193,9 @@ NoteLayer::setProperty(const PropertyName &name, int value)
} else if (name == "Scale Units") {
auto model = ModelById::getAs<NoteModel>(m_model);
if (model) {
- model->setScaleUnits
- (UnitDatabase::getInstance()->getUnitById(value));
+ QString unit = UnitDatabase::getInstance()->getUnitById(value);
+ model->setScaleUnits(unit);
+ m_modelUsesHz = (unit.toLower() == "hz");
emit modelChanged(m_model);
}
} else {
@@ -215,15 +218,43 @@ NoteLayer::isLayerScrollable(const LayerGeometryProvider *v) const
return !v->shouldIlluminateLocalFeatures(this, discard);
}
-bool
-NoteLayer::shouldConvertMIDIToHz() const
+double
+NoteLayer::valueOf(const Event &e) const
+{
+ return convertValueFromEventValue(e.getValue());
+}
+
+Event
+NoteLayer::eventWithValue(const Event &e, double value) const
{
- QString unit = getScaleUnits();
- return (unit != "Hz");
-// if (unit == "" ||
-// unit.startsWith("MIDI") ||
-// unit.startsWith("midi")) return true;
-// return false;
+ return e.withValue(convertValueToEventValue(value));
+}
+
+double
+NoteLayer::convertValueFromEventValue(float eventValue) const
+{
+ if (m_modelUsesHz) {
+ return eventValue;
+ } else {
+ double v = eventValue;
+ if (v < 0) v = 0;
+ if (v > 127) v = 127;
+ int p = int(round(v));
+ double c = 100.0 * (v - p);
+ return Pitch::getFrequencyForPitch(p, c);
+ }
+}
+
+float
+NoteLayer::convertValueToEventValue(double value) const
+{
+ if (m_modelUsesHz) {
+ return float(value);
+ } else {
+ float c = 0;
+ int p = Pitch::getPitchForFrequency(value, &c);
+ return float(p) + c / 100.f;
+ }
}
bool
@@ -232,17 +263,14 @@ NoteLayer::getValueExtents(double &min, double &max,
{
auto model = ModelById::getAs<NoteModel>(m_model);
if (!model) return false;
- min = model->getValueMinimum();
- max = model->getValueMaximum();
- if (shouldConvertMIDIToHz()) {
- unit = "Hz";
- min = Pitch::getFrequencyForPitch(int(lrint(min)));
- max = Pitch::getFrequencyForPitch(int(lrint(max + 1)));
- } else unit = getScaleUnits();
+ min = convertValueFromEventValue(model->getValueMinimum());
+ max = convertValueFromEventValue(model->getValueMaximum());
+ min /= 1.06;
+ max *= 1.06;
+ unit = "Hz";
- if (m_verticalScale == MIDIRangeScale ||
- m_verticalScale == LogScale) {
+ if (m_verticalScale != LinearScale) {
logarithmic = true;
}
@@ -262,20 +290,16 @@ NoteLayer::getDisplayExtents(double &min, double &max) const
}
if (m_scaleMinimum == m_scaleMaximum) {
- min = model->getValueMinimum();
- max = model->getValueMaximum();
+ QString unit;
+ bool log = false;
+ getValueExtents(min, max, log, unit);
} else {
min = m_scaleMinimum;
max = m_scaleMaximum;
}
- if (shouldConvertMIDIToHz()) {
- min = Pitch::getFrequencyForPitch(int(lrint(min)));
- max = Pitch::getFrequencyForPitch(int(lrint(max + 1)));
- }
-
#ifdef DEBUG_NOTE_LAYER
- cerr << "NoteLayer::getDisplayExtents: min = " << min << ", max = " << max << " (m_scaleMinimum = " << m_scaleMinimum << ", m_scaleMaximum = " << m_scaleMaximum << ")" << endl;
+ SVCERR << "NoteLayer::getDisplayExtents: min = " << min << ", max = " << max << " (m_scaleMinimum = " << m_scaleMinimum << ", m_scaleMaximum = " << m_scaleMaximum << ")" << endl;
#endif
return true;
@@ -298,7 +322,7 @@ NoteLayer::setDisplayExtents(double min, double max)
m_scaleMaximum = max;
#ifdef DEBUG_NOTE_LAYER
- cerr << "NoteLayer::setDisplayExtents: min = " << min << ", max = " << max << endl;
+ SVCERR << "NoteLayer::setDisplayExtents: min = " << min << ", max = " << max << endl;
#endif
emit layerParametersChanged();
@@ -377,7 +401,7 @@ NoteLayer::setVerticalZoomStep(int step)
}
#ifdef DEBUG_NOTE_LAYER
- cerr << "NoteLayer::setVerticalZoomStep: " << step << ": " << newmin << " -> " << newmax << " (range " << newdist << ")" << endl;
+ SVCERR << "NoteLayer::setVerticalZoomStep: " << step << ": " << newmin << " -> " << newmax << " (range " << newdist << ")" << endl;
#endif
setDisplayExtents(newmin, newmax);
@@ -443,7 +467,7 @@ NoteLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, Event &point)
int nearestDistance = -1;
for (const auto &p: onPoints) {
- int distance = getYForValue(v, p.getValue()) - y;
+ int distance = getYForValue(v, valueOf(p)) - y;
if (distance < 0) distance = -distance;
if (nearestDistance == -1 || distance < nearestDistance) {
nearestDistance = distance;
@@ -477,12 +501,13 @@ NoteLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
for (i = points.begin(); i != points.end(); ++i) {
- int y = getYForValue(v, i->getValue());
+ int y = getYForValue(v, valueOf(*i));
int h = 3;
if (model->getValueQuantization() != 0.0) {
h = y - getYForValue
- (v, i->getValue() + model->getValueQuantization());
+ (v, convertValueFromEventValue(i->getValue() +
+ model->getValueQuantization()));
if (h < 3) h = 3;
}
@@ -501,28 +526,27 @@ NoteLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
QString pitchText;
- float value = note.getValue();
-
- if (shouldConvertMIDIToHz()) {
-
- int mnote = int(lrint(value));
- int cents = int(lrint((value - float(mnote)) * 100));
- double freq = Pitch::getFrequencyForPitch(mnote, cents);
- pitchText = tr("%1 (%2, %3 Hz)")
- .arg(Pitch::getPitchLabel(mnote, cents))
- .arg(mnote)
- .arg(freq);
-
- } else if (getScaleUnits() == "Hz") {
+ if (m_modelUsesHz) {
+ float value = note.getValue();
+
pitchText = tr("%1 Hz (%2, %3)")
.arg(value)
.arg(Pitch::getPitchLabelForFrequency(value))
.arg(Pitch::getPitchForFrequency(value));
} else {
- pitchText = tr("%1 %2")
- .arg(value).arg(getScaleUnits());
+
+ float eventValue = note.getValue();
+ double value = convertValueFromEventValue(eventValue);
+
+ int mnote = int(lrint(eventValue));
+ int cents = int(lrint((eventValue - float(mnote)) * 100));
+
+ pitchText = tr("%1 (%2, %3 Hz)")
+ .arg(Pitch::getPitchLabel(mnote, cents))
+ .arg(eventValue)
+ .arg(value);
}
QString text;
@@ -540,7 +564,8 @@ NoteLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
.arg(note.getLabel());
}
- pos = QPoint(v->getXForFrame(note.getFrame()), getYForValue(v, value));
+ pos = QPoint(v->getXForFrame(note.getFrame()),
+ getYForValue(v, valueOf(note)));
return text;
}
@@ -593,24 +618,15 @@ NoteLayer::getScaleExtents(LayerGeometryProvider *v, double &min, double &max, b
auto model = ModelById::getAs<NoteModel>(m_model);
if (!model) return;
- QString queryUnits;
- if (shouldConvertMIDIToHz()) queryUnits = "Hz";
- else queryUnits = getScaleUnits();
-
if (shouldAutoAlign()) {
- if (!v->getVisibleExtentsForUnit(queryUnits, min, max, log)) {
-
- min = model->getValueMinimum();
- max = model->getValueMaximum();
+ if (!v->getVisibleExtentsForUnit("Hz", min, max, log)) {
- if (shouldConvertMIDIToHz()) {
- min = Pitch::getFrequencyForPitch(int(lrint(min)));
- max = Pitch::getFrequencyForPitch(int(lrint(max + 1)));
- }
+ QString unit;
+ getValueExtents(min, max, log, unit);
#ifdef DEBUG_NOTE_LAYER
- cerr << "NoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << endl;
+ SVCERR << "NoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << endl;
#endif
} else if (log) {
@@ -618,24 +634,15 @@ NoteLayer::getScaleExtents(LayerGeometryProvider *v, double &min, double &max, b
LogRange::mapRange(min, max);
#ifdef DEBUG_NOTE_LAYER
- cerr << "NoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << endl;
+ SVCERR << "NoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << endl;
#endif
-
}
} else {
getDisplayExtents(min, max);
- if (m_verticalScale == MIDIRangeScale) {
- min = Pitch::getFrequencyForPitch(0);
- max = Pitch::getFrequencyForPitch(127);
- } else if (shouldConvertMIDIToHz()) {
- min = Pitch::getFrequencyForPitch(int(lrint(min)));
- max = Pitch::getFrequencyForPitch(int(lrint(max + 1)));
- }
-
- if (m_verticalScale == LogScale || m_verticalScale == MIDIRangeScale) {
+ if (m_verticalScale != LinearScale) {
LogRange::mapRange(min, max);
log = true;
}
@@ -654,27 +661,19 @@ NoteLayer::getYForValue(LayerGeometryProvider *v, double val) const
getScaleExtents(v, min, max, logarithmic);
#ifdef DEBUG_NOTE_LAYER
- cerr << "NoteLayer[" << this << "]::getYForValue(" << val << "): min = " << min << ", max = " << max << ", log = " << logarithmic << endl;
-#endif
-
- if (shouldConvertMIDIToHz()) {
- val = Pitch::getFrequencyForPitch(int(lrint(val)),
- int(lrint((val - rint(val)) * 100)));
-#ifdef DEBUG_NOTE_LAYER
- cerr << "shouldConvertMIDIToHz true, val now = " << val << endl;
+ SVCERR << "NoteLayer[" << this << "]::getYForValue(" << val << "): min = " << min << ", max = " << max << ", log = " << logarithmic << endl;
#endif
- }
if (logarithmic) {
val = LogRange::map(val);
#ifdef DEBUG_NOTE_LAYER
- cerr << "logarithmic true, val now = " << val << endl;
+ SVCERR << "logarithmic true, val now = " << val << endl;
#endif
}
int y = int(h - ((val - min) * h) / (max - min)) - 1;
#ifdef DEBUG_NOTE_LAYER
- cerr << "y = " << y << endl;
+ SVCERR << "y = " << y << endl;
#endif
return y;
}
@@ -694,10 +693,6 @@ NoteLayer::getValueForY(LayerGeometryProvider *v, int y) const
val = pow(10.0, val);
}
- if (shouldConvertMIDIToHz()) {
- val = Pitch::getPitchForFrequency(val);
- }
-
return val;
}
@@ -719,7 +714,9 @@ NoteLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
// Profiler profiler("NoteLayer::paint", true);
- int x0 = rect.left(), x1 = rect.right();
+ int x0 = rect.left();
+ int x1 = x0 + rect.width();
+
sv_frame_t frame0 = v->getFrameForX(x0);
sv_frame_t frame1 = v->getFrameForX(x1);
@@ -734,20 +731,20 @@ NoteLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
// SVDEBUG << "NoteLayer::paint: resolution is "
// << model->getResolution() << " frames" << endl;
- double min = model->getValueMinimum();
- double max = model->getValueMaximum();
+ double min = convertValueFromEventValue(model->getValueMinimum());
+ double max = convertValueFromEventValue(model->getValueMaximum());
if (max == min) max = min + 1.0;
QPoint localPos;
Event illuminatePoint;
bool shouldIlluminate = false;
- if (v->shouldIlluminateLocalFeatures(this, localPos)) {
- shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(),
- illuminatePoint);
- } else if (m_editIsOpen) {
+ if (m_editing || m_editIsOpen) {
shouldIlluminate = true;
illuminatePoint = m_editingPoint;
+ } else if (v->shouldIlluminateLocalFeatures(this, localPos)) {
+ shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(),
+ illuminatePoint);
}
paint.save();
@@ -759,12 +756,14 @@ NoteLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
const Event &p(*i);
int x = v->getXForFrame(p.getFrame());
- int y = getYForValue(v, p.getValue());
+ int y = getYForValue(v, valueOf(p));
int w = v->getXForFrame(p.getFrame() + p.getDuration()) - x;
int h = 3;
if (model->getValueQuantization() != 0.0) {
- h = y - getYForValue(v, p.getValue() + model->getValueQuantization());
+ h = y - getYForValue
+ (v, convertValueFromEventValue
+ (p.getValue() + model->getValueQuantization()));
if (h < 3) h = 3;
}
@@ -782,7 +781,17 @@ NoteLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
// which is too new for us
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- QString vlabel = QString("%1%2").arg(p.getValue()).arg(getScaleUnits());
+ QString vlabel;
+ if (m_modelUsesHz) {
+ vlabel = QString("%1%2")
+ .arg(p.getValue())
+ .arg(model->getScaleUnits());
+ } else {
+ vlabel = QString("%1 %2")
+ .arg(p.getValue())
+ .arg(model->getScaleUnits());
+ }
+
PaintAssistant::drawVisibleText(v, paint,
x - paint.fontMetrics().width(vlabel) - 2,
y + paint.fontMetrics().height()/2
@@ -814,7 +823,7 @@ NoteLayer::getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &paint
return 0;
}
- if (m_verticalScale == LogScale || m_verticalScale == MIDIRangeScale) {
+ if (m_verticalScale != LinearScale) {
return LogNumericalScale().getWidth(v, paint) + 10; // for piano
} else {
return LinearNumericalScale().getWidth(v, paint);
@@ -842,7 +851,7 @@ NoteLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, Q
LinearNumericalScale().paintVertical(v, this, paint, 0, min, max);
}
- if (logarithmic && (getScaleUnits() == "Hz")) {
+ if (logarithmic) {
PianoScale().paintPianoVertical
(v, paint, QRect(w - 10, 0, 10, h),
LogRange::unmap(min),
@@ -873,8 +882,10 @@ NoteLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e)
frame = frame / model->getResolution() * model->getResolution();
double value = getValueForY(v, e->y());
+ float eventValue = convertValueToEventValue(value);
+ eventValue = roundf(eventValue);
- m_editingPoint = Event(frame, float(value), 0, 0.8f, tr("New Point"));
+ m_editingPoint = Event(frame, eventValue, 0, 0.8f, tr("New Point"));
m_originalPoint = m_editingPoint;
if (m_editingCommand) finish(m_editingCommand);
@@ -897,6 +908,8 @@ NoteLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e)
frame = frame / model->getResolution() * model->getResolution();
double newValue = getValueForY(v, e->y());
+ float newEventValue = convertValueToEventValue(newValue);
+ newEventValue = roundf(newEventValue);
sv_frame_t newFrame = m_editingPoint.getFrame();
sv_frame_t newDuration = frame - newFrame;
@@ -910,8 +923,8 @@ NoteLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e)
m_editingCommand->remove(m_editingPoint);
m_editingPoint = m_editingPoint
.withFrame(newFrame)
- .withValue(float(newValue))
- .withDuration(newDuration);
+ .withDuration(newDuration)
+ .withValue(newEventValue);
m_editingCommand->add(m_editingPoint);
}
@@ -981,7 +994,7 @@ NoteLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e)
m_originalPoint = m_editingPoint;
m_dragPointX = v->getXForFrame(m_editingPoint.getFrame());
- m_dragPointY = getYForValue(v, m_editingPoint.getValue());
+ m_dragPointY = getYForValue(v, valueOf(m_editingPoint));
if (m_editingCommand) {
finish(m_editingCommand);
@@ -1010,7 +1023,9 @@ NoteLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e)
if (frame < 0) frame = 0;
frame = frame / model->getResolution() * model->getResolution();
- double value = getValueForY(v, newy);
+ double newValue = getValueForY(v, newy);
+ float newEventValue = convertValueToEventValue(newValue);
+ newEventValue = roundf(newEventValue);
if (!m_editingCommand) {
m_editingCommand = new ChangeEventsCommand
@@ -1020,7 +1035,7 @@ NoteLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e)
m_editingCommand->remove(m_editingPoint);
m_editingPoint = m_editingPoint
.withFrame(frame)
- .withValue(float(value));
+ .withValue(newEventValue);
m_editingCommand->add(m_editingPoint);
}
@@ -1270,7 +1285,9 @@ NoteLayer::paste(LayerGeometryProvider *v, const Clipboard &from,
void
NoteLayer::addNoteOn(sv_frame_t frame, int pitch, int velocity)
{
- m_pendingNoteOns.insert(Event(frame, float(pitch), 0,
+ double value = Pitch::getFrequencyForPitch(pitch);
+ float eventValue = convertValueToEventValue(value);
+ m_pendingNoteOns.insert(Event(frame, eventValue, 0,
float(velocity) / 127.f, QString()));
}
@@ -1283,8 +1300,10 @@ NoteLayer::addNoteOff(sv_frame_t frame, int pitch)
i != m_pendingNoteOns.end(); ++i) {
Event p = *i;
+ double value = valueOf(p);
+ int eventPitch = Pitch::getPitchForFrequency(value);
- if (lrintf(p.getValue()) == pitch) {
+ if (eventPitch == pitch) {
m_pendingNoteOns.erase(i);
Event note = p.withDuration(frame - p.getFrame());
if (model) {