# HG changeset patch # User Chris Cannam # Date 1143649465 0 # Node ID 193b569a975fb26965aa3c7d49ad16b751b8de4f # Parent c4fff27cd651d2783ae4e5b460fbec084785152f * Add scale lines to waveform layer * Various fixes to vertical scale drawing for waveform and time-value layers * Make log/linear scale have an effect for time-value layer segmentation mode diff -r c4fff27cd651 -r 193b569a975f layer/TimeValueLayer.cpp --- a/layer/TimeValueLayer.cpp Wed Mar 29 12:35:17 2006 +0000 +++ b/layer/TimeValueLayer.cpp Wed Mar 29 16:24:25 2006 +0000 @@ -417,6 +417,28 @@ return min + (float(h - y) * float(max - min)) / h; } +QColor +TimeValueLayer::getColourForValue(float val) const +{ + float min = m_model->getValueMinimum(); + float max = m_model->getValueMaximum(); + if (max == min) max = min + 1.0; + + if (m_verticalScale == FrequencyScale || m_verticalScale == LogScale) { + min = (min < 0.0) ? -log10(-min) : (min == 0.0) ? 0.0 : log10(min); + max = (max < 0.0) ? -log10(-max) : (max == 0.0) ? 0.0 : log10(max); + val = (val < 0.0) ? -log10(-val) : (val == 0.0) ? 0.0 : log10(val); + } else if (m_verticalScale == PlusMinusOneScale) { + min = -1.0; + max = 1.0; + } + + int iv = ((val - min) / (max - min)) * 255.999; + + QColor colour = QColor::fromHsv(256 - iv, iv / 2 + 128, iv); + return QColor(colour.red(), colour.green(), colour.blue(), 120); +} + void TimeValueLayer::paint(View *v, QPainter &paint, QRect rect) const { @@ -497,10 +519,7 @@ paint.setPen(m_colour); if (m_plotStyle == PlotSegmentation) { - int value = ((p.value - min) / (max - min)) * 255.999; - QColor colour = QColor::fromHsv(256 - value, value / 2 + 128, value); - paint.setBrush(QColor(colour.red(), colour.green(), colour.blue(), - 120)); + paint.setBrush(getColourForValue(p.value)); labelY = v->height(); } else if (m_plotStyle == PlotLines || m_plotStyle == PlotCurve) { @@ -617,35 +636,82 @@ int TimeValueLayer::getVerticalScaleWidth(View *v, QPainter &paint) const { - if (m_plotStyle == PlotSegmentation) return 0; - return paint.fontMetrics().width("+0.000e+00") + 15; + int w = paint.fontMetrics().width("-000.000"); + if (m_plotStyle == PlotSegmentation) return w + 20; + else return w + 10; } void TimeValueLayer::paintVerticalScale(View *v, QPainter &paint, QRect rect) const { if (!m_model) return; - if (m_plotStyle == PlotSegmentation) return; - float val = m_model->getValueMinimum(); - float inc = (m_model->getValueMaximum() - val) / 10; + int h = v->height(); + + int n = 10; + + float max = m_model->getValueMaximum(); + float min = m_model->getValueMinimum(); + float val = min; + float inc = (max - val) / n; char buffer[40]; int w = getVerticalScaleWidth(v, paint); - while (val < m_model->getValueMaximum()) { - int y = getYForValue(v, val); -// QString label = QString("%1").arg(val); - sprintf(buffer, "%+.3e", val); + int tx = 5; + + int boxx = 5, boxy = 5; + if (m_model->getScaleUnits() != "") { + boxy += paint.fontMetrics().height(); + } + int boxw = 10, boxh = h - boxy - 5; + + if (m_plotStyle == PlotSegmentation) { + tx += boxx + boxw; + paint.drawRect(boxx, boxy, boxw, boxh); + } + + if (m_plotStyle == PlotSegmentation) { + paint.save(); + for (int y = 0; y < boxh; ++y) { + float val = ((boxh - y) * (max - min)) / boxh + min; + paint.setPen(getColourForValue(val)); + paint.drawLine(boxx + 1, y + boxy + 1, boxx + boxw, y + boxy + 1); + } + paint.restore(); + } + + for (int i = 0; i < n; ++i) { + + int y, ty; + bool drawText = true; + + if (m_plotStyle == PlotSegmentation) { + y = boxy + int(boxh - ((val - min) * boxh) / (max - min)); + ty = y; + } else { + if (i == n-1) { + if (m_model->getScaleUnits() != "") drawText = false; + } + y = getYForValue(v, val); + ty = y - paint.fontMetrics().height() + + paint.fontMetrics().ascent(); + } + + sprintf(buffer, "%.3f", val); QString label = QString(buffer); - paint.drawLine(w - 5, y, w, y);// 100 - 10, y, 100, y); - paint.drawText(5, // 100 - 15 - paint.fontMetrics().width(label), - y - paint.fontMetrics().height() + paint.fontMetrics().ascent(), - label); + + if (m_plotStyle != PlotSegmentation) { + paint.drawLine(w - 5, y, w, y); + } else { + paint.drawLine(boxx + boxw - boxw/3, y, boxx + boxw, y); + } + + if (drawText) paint.drawText(tx, ty, label); val += inc; } - + if (m_model->getScaleUnits() != "") { paint.drawText(5, 5 + paint.fontMetrics().ascent(), m_model->getScaleUnits()); diff -r c4fff27cd651 -r 193b569a975f layer/TimeValueLayer.h --- a/layer/TimeValueLayer.h Wed Mar 29 12:35:17 2006 +0000 +++ b/layer/TimeValueLayer.h Wed Mar 29 16:24:25 2006 +0000 @@ -105,6 +105,8 @@ int getYForValue(View *, float value) const; float getValueForY(View *, int y) const; + QColor getColourForValue(float value) const; + SparseTimeValueModel::PointList getLocalPoints(View *v, int) const; SparseTimeValueModel *m_model; diff -r c4fff27cd651 -r 193b569a975f layer/WaveformLayer.cpp --- a/layer/WaveformLayer.cpp Wed Mar 29 12:35:17 2006 +0000 +++ b/layer/WaveformLayer.cpp Wed Mar 29 16:24:25 2006 +0000 @@ -78,7 +78,11 @@ list.push_back(tr("Scale")); list.push_back(tr("Gain")); list.push_back(tr("Normalize Visible Area")); - list.push_back(tr("Channels")); + + if (m_model && m_model->getChannelCount() > 1 && m_channel == -1) { + list.push_back(tr("Channels")); + } + return list; } @@ -369,6 +373,9 @@ return !m_autoNormalize; } +static float meterdbs[] = { -40, -30, -20, -15, -10, + -5, -3, -2, -1, -0.5, 0 }; + void WaveformLayer::paint(View *v, QPainter &viewPainter, QRect rect) const { @@ -487,28 +494,6 @@ int prevRangeBottom = -1, prevRangeTop = -1; QColor prevRangeBottomColour = m_colour, prevRangeTopColour = m_colour; - int m = (h / channels) / 2; - int my = m + (((ch - minChannel) * h) / channels); - -// std::cerr << "ch = " << ch << ", channels = " << channels << ", m = " << m << ", my = " << my << ", h = " << h << std::endl; - - if (my - m > y1 || my + m < y0) continue; - - paint->setPen(greys[0]); - paint->drawLine(x0, my, x1, my); - - if (frame1 <= 0) continue; - - size_t modelZoomLevel = zoomLevel; - - ranges = m_model->getRanges - (ch, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel); - - if (mergingChannels || mixingChannels) { - otherChannelRanges = m_model->getRanges - (1, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel); - } - m_effectiveGains[ch] = m_gain; if (m_autoNormalize) { @@ -529,6 +514,80 @@ float gain = m_effectiveGains[ch]; + int m = (h / channels) / 2; + int my = m + (((ch - minChannel) * h) / channels); + +// std::cerr << "ch = " << ch << ", channels = " << channels << ", m = " << m << ", my = " << my << ", h = " << h << std::endl; + + if (my - m > y1 || my + m < y0) continue; + + if ((m_scale == dBScale || m_scale == MeterScale) && + m_channelMode != MergeChannels) { + m = (h / channels); + my = m + (((ch - minChannel) * h) / channels); + } + + paint->setPen(greys[0]); + paint->drawLine(x0, my, x1, my); + + int n = 10; + int py = -1; + + if (v->hasLightBackground()) { + + paint->setPen(QColor(240, 240, 240)); + + for (int i = 1; i < n; ++i) { + + float val = 0.0, nval = 0.0; + + switch (m_scale) { + + case LinearScale: + val = (i * gain) / n; + if (i > 0) nval = -val; + break; + + case MeterScale: + val = AudioLevel::dB_to_multiplier(meterdbs[i]) * gain; + break; + + case dBScale: + val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10) * gain; + break; + } + + if (val < -1.0 || val > 1.0) continue; + + int y = getYForValue(v, m_scale, val, ch, minChannel, maxChannel); + + if (py >= 0 && abs(y - py) < 10) continue; + else py = y; + + int ny = y; + if (nval != 0.0) { + ny = getYForValue(v, m_scale, nval, ch, minChannel, maxChannel); + } + + paint->drawLine(x0, y, x1, y); + if (ny != y) { + paint->drawLine(x0, ny, x1, ny); + } + } + } + + if (frame1 <= 0) continue; + + size_t modelZoomLevel = zoomLevel; + + ranges = m_model->getRanges + (ch, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel); + + if (mergingChannels || mixingChannels) { + otherChannelRanges = m_model->getRanges + (1, frame0 < 0 ? 0 : frame0, frame1, modelZoomLevel); + } + for (int x = x0; x <= x1; ++x) { range = RangeSummarisableTimeValueModel::Range(); @@ -832,6 +891,45 @@ } int +WaveformLayer::getYForValue(View *v, Scale scale, float value, size_t channel, + size_t minChannel, size_t maxChannel) const +{ + if (maxChannel < minChannel || channel < minChannel) return 0; + + int w = v->width(); + int h = v->height(); + + int channels = maxChannel - minChannel + 1; + int m = (h / channels) / 2; + int my = m + (((channel - minChannel) * h) / channels); + + if ((m_scale == dBScale || m_scale == MeterScale) && + m_channelMode != MergeChannels) { + m = (h / channels); + my = m + (((channel - minChannel) * h) / channels); + } + + int vy = 0; + + switch (scale) { + + case LinearScale: + vy = int(m * value); + break; + + case MeterScale: + vy = AudioLevel::multiplier_to_preview(value, m); + break; + + case dBScale: + vy = dBscale(value, m); + break; + } + + return my - vy; +} + +int WaveformLayer::getVerticalScaleWidth(View *v, QPainter &paint) const { if (m_scale == LinearScale) { @@ -864,75 +962,101 @@ for (size_t ch = minChannel; ch <= maxChannel; ++ch) { - int m = (h / channels) / 2; - int my = m + (((ch - minChannel) * h) / channels); - int py = -1; + int lastLabelledY = -1; if (ch < m_effectiveGains.size()) gain = m_effectiveGains[ch]; - for (int i = 0; i <= 10; ++i) { + int n = 10; - int vy = 0; + for (int i = 0; i <= n; ++i) { + + float val = 0.0, nval = 0.0; QString text = ""; - if (m_scale == LinearScale) { + switch (m_scale) { + + case LinearScale: + val = (i * gain) / n; + text = QString("%1").arg(float(i) / n); + if (i == 0) text = "0.0"; + else { + nval = -val; + if (i == n) text = "1.0"; + } + break; - vy = int((m * i * gain) / 10); + case MeterScale: + val = AudioLevel::dB_to_multiplier(meterdbs[i]) * gain; + text = QString("%1").arg(meterdbs[i]); + if (i == n) text = tr("0dB"); + if (i == 0) { + text = tr("-Inf"); + val = 0.0; + } + break; - text = QString("%1").arg(float(i) / 10.0); - if (i == 0) text = "0.0"; - if (i == 10) text = "1.0"; + case dBScale: + val = AudioLevel::dB_to_multiplier(-(10*n) + i * 10) * gain; + text = QString("%1").arg(-(10*n) + i * 10); + if (i == n) text = tr("0dB"); + if (i == 0) { + text = tr("-Inf"); + val = 0.0; + } + break; + } - } else { + if (val < -1.0 || val > 1.0) continue; - int db; - bool minvalue = false; - - if (m_scale == MeterScale) { - static int dbs[] = { -50, -40, -30, -20, -15, - -10, -5, -3, -2, -1, 0 }; - db = dbs[i]; - if (db == -50) minvalue = true; - vy = AudioLevel::multiplier_to_preview - (AudioLevel::dB_to_multiplier(db) * gain, m); - } else { - db = -100 + i * 10; - if (db == -100) minvalue = true; - vy = dBscale - (AudioLevel::dB_to_multiplier(db) * gain, m); - } + int y = getYForValue(v, m_scale, val, ch, minChannel, maxChannel); - text = QString("%1").arg(db); - if (db == 0) text = tr("0dB"); - if (minvalue) { - text = tr("-Inf"); - vy = 0; - } - } + int ny = y; + if (nval != 0.0) { + ny = getYForValue(v, m_scale, nval, ch, minChannel, maxChannel); + } - if (vy < 0) vy = -vy; -// if (vy >= m - 1) continue; + bool spaceForLabel = (i == 0 || + abs(y - lastLabelledY) >= textHeight - 1); - if (py >= 0 && (vy - py) < textHeight - 1) { - paint.drawLine(w - 4, my - vy, w, my - vy); - if (vy > 0) paint.drawLine(w - 4, my + vy, w, my + vy); - continue; - } + if (spaceForLabel) { - paint.drawLine(w - 7, my - vy, w, my - vy); - if (vy > 0) paint.drawLine(w - 7, my + vy, w, my + vy); + int tx = 3; + if (m_scale != LinearScale) { + tx = w - 10 - paint.fontMetrics().width(text); + } + + int ty = y; + if (ty < paint.fontMetrics().ascent()) { + ty = paint.fontMetrics().ascent(); + } else if (ty > h - paint.fontMetrics().descent()) { + ty = h - paint.fontMetrics().descent(); + } else { + ty += toff; + } + paint.drawText(tx, ty, text); - int tx = 3; - if (m_scale != LinearScale) { - tx = w - 10 - paint.fontMetrics().width(text); - } - - if (vy >= m - 1) continue; + lastLabelledY = ty - toff; - paint.drawText(tx, my - vy + toff, text); - if (vy > 0) paint.drawText(tx, my + vy + toff, text); - - py = vy; + if (ny != y) { + ty = ny; + if (ty < paint.fontMetrics().ascent()) { + ty = paint.fontMetrics().ascent(); + } else if (ty > h - paint.fontMetrics().descent()) { + ty = h - paint.fontMetrics().descent(); + } else { + ty += toff; + } + paint.drawText(tx, ty, text); + } + + paint.drawLine(w - 7, y, w, y); + if (ny != y) paint.drawLine(w - 7, ny, w, ny); + + } else { + + paint.drawLine(w - 4, y, w, y); + if (ny != y) paint.drawLine(w - 4, ny, w, ny); + } } } } diff -r c4fff27cd651 -r 193b569a975f layer/WaveformLayer.h --- a/layer/WaveformLayer.h Wed Mar 29 12:35:17 2006 +0000 +++ b/layer/WaveformLayer.h Wed Mar 29 16:24:25 2006 +0000 @@ -186,6 +186,9 @@ size_t getChannelArrangement(size_t &min, size_t &max, bool &merging, bool &mixing) const; + int getYForValue(View *v, Scale scale, float value, size_t channel, + size_t minChannel, size_t maxChannel) const; + float m_gain; bool m_autoNormalize; QColor m_colour; diff -r c4fff27cd651 -r 193b569a975f widgets/Pane.cpp --- a/widgets/Pane.cpp Wed Mar 29 12:35:17 2006 +0000 +++ b/widgets/Pane.cpp Wed Mar 29 16:24:25 2006 +0000 @@ -162,7 +162,7 @@ paint.setPen(Qt::black); paint.setBrush(Qt::white); - paint.drawRect(0, 0, verticalScaleWidth, height()); + paint.drawRect(0, -1, verticalScaleWidth, height()+1); paint.setBrush(Qt::NoBrush); (*vi)->paintVerticalScale