# HG changeset patch # User Chris Cannam # Date 1183381457 0 # Node ID b9380f679f70a462edf3f6178db12cb88955f46a # Parent e954c00cbe559e219da0ba187893b1a78fc9ddcc * Fix centre line position * Fix failure to update overview when generating peaks from wav file * Provide y-coordinate scale values and differences for spectrum measurement mode, and fix values for waveform (inc dB for both) * Add Printer colour scheme (may be futile) diff -r e954c00cbe55 -r b9380f679f70 layer/ColourMapper.cpp --- a/layer/ColourMapper.cpp Fri Jun 29 16:50:59 2007 +0000 +++ b/layer/ColourMapper.cpp Mon Jul 02 13:04:17 2007 +0000 @@ -39,7 +39,7 @@ int ColourMapper::getColourMapCount() { - return 10; + return 11; } QString @@ -59,6 +59,7 @@ case FruitSalad: return tr("Fruit Salad"); case Banded: return tr("Banded"); case Highlight: return tr("Highlight"); + case Printer: return tr("Printer"); } return tr(""); @@ -157,6 +158,28 @@ case Highlight: if (norm > 0.99) return Qt::white; else return Qt::darkBlue; + + case Printer: + if (norm > 0.8) { + r = 1.f; + } else if (norm > 0.7) { + r = 0.9f; + } else if (norm > 0.6) { + r = 0.8f; + } else if (norm > 0.5) { + r = 0.7f; + } else if (norm > 0.4) { + r = 0.6f; + } else if (norm > 0.3) { + r = 0.5f; + } else if (norm > 0.2) { + r = 0.4f; + } else { + r = 0.f; + } + r = g = b = 1.f - r; + hsv = false; + break; } if (hsv) { @@ -203,6 +226,9 @@ case Highlight: return Qt::red; + + case Printer: + return Qt::red; } return Qt::white; diff -r e954c00cbe55 -r b9380f679f70 layer/ColourMapper.h --- a/layer/ColourMapper.h Fri Jun 29 16:50:59 2007 +0000 +++ b/layer/ColourMapper.h Mon Jul 02 13:04:17 2007 +0000 @@ -42,7 +42,8 @@ BlueOnBlack, FruitSalad, Banded, - Highlight + Highlight, + Printer }; int getMap() const { return m_map; } diff -r e954c00cbe55 -r b9380f679f70 layer/Layer.cpp --- a/layer/Layer.cpp Fri Jun 29 16:50:59 2007 +0000 +++ b/layer/Layer.cpp Mon Jul 02 13:04:17 2007 +0000 @@ -123,6 +123,20 @@ } bool +Layer::getYScaleDifference(const View *v, int y0, int y1, + float &diff, QString &unit) const +{ + float v0, v1; + if (!getYScaleValue(v, y0, v0, unit) || + !getYScaleValue(v, y1, v1, unit)) { + diff = 0.f; + return false; + } + diff = fabsf(v1 - v0); + return true; +} + +bool Layer::MeasureRect::operator<(const MeasureRect &mr) const { if (haveFrames) { @@ -236,8 +250,7 @@ m_draggingRect.pixrect = QRect(m_draggingRect.pixrect.x(), m_draggingRect.pixrect.y(), e->x() - m_draggingRect.pixrect.x(), - e->y() - m_draggingRect.pixrect.y()) - .normalized(); + e->y() - m_draggingRect.pixrect.y()); setMeasureRectYCoord(v, m_draggingRect, false, e->y()); @@ -328,8 +341,6 @@ i->pixrect = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height()); updateMeasureRectYCoords(v, *i); - - i->pixrect = i->pixrect.normalized(); } } @@ -396,11 +407,10 @@ } QRect pr = QRect(x0, r.pixrect.y(), x1 - x0, r.pixrect.height()); - r.pixrect = pr; } - - v->drawMeasurementRect(paint, this, r.pixrect, focus); + + v->drawMeasurementRect(paint, this, r.pixrect.normalized(), focus); } QString diff -r e954c00cbe55 -r b9380f679f70 layer/Layer.h --- a/layer/Layer.h Fri Jun 29 16:50:59 2007 +0000 +++ b/layer/Layer.h Mon Jul 02 13:04:17 2007 +0000 @@ -367,6 +367,15 @@ } /** + * Return the difference between the values at the given y + * coordinates in the given view, and the unit of the difference. + * The default implementation just calls getYScaleValue twice and + * returns the difference, with the same unit. + */ + virtual bool getYScaleDifference(const View *v, int y0, int y1, + float &diff, QString &unit) const; + + /** * Get the number of vertical zoom steps available for this layer. * If vertical zooming is not available, return 0. The meaning of * "zooming" is entirely up to the layer -- changing the zoom diff -r e954c00cbe55 -r b9380f679f70 layer/SliceLayer.cpp --- a/layer/SliceLayer.cpp Fri Jun 29 16:50:59 2007 +0000 +++ b/layer/SliceLayer.cpp Mon Jul 02 13:04:17 2007 +0000 @@ -225,6 +225,85 @@ return bin; } +float +SliceLayer::getYForValue(float value, const View *v, float &norm) const +{ + norm = 0.f; + + if (m_yorigins.find(v) == m_yorigins.end()) return 0; + + value *= m_gain; + + int yorigin = m_yorigins[v]; + int h = m_heights[v]; + float thresh = -80.f; + + float y = 0.f; + + if (h <= 0) return y; + + switch (m_energyScale) { + + case dBScale: + { + float db = thresh; + if (value > 0.f) db = 10.f * log10f(value); + if (db < thresh) db = thresh; + norm = (db - thresh) / -thresh; + y = yorigin - (float(h) * norm); + break; + } + + case MeterScale: + y = AudioLevel::multiplier_to_preview(value, h); + norm = float(y) / float(h); + y = yorigin - y; + break; + + default: + norm = value; + y = yorigin - (float(h) * value); + break; + } + + return y; +} + +float +SliceLayer::getValueForY(float y, const View *v) const +{ + float value = 0.f; + + if (m_yorigins.find(v) == m_yorigins.end()) return value; + + int yorigin = m_yorigins[v]; + int h = m_heights[v]; + float thresh = -80.f; + + if (h <= 0) return value; + + y = yorigin - y; + + switch (m_energyScale) { + + case dBScale: + { + float db = ((y / h) * -thresh) + thresh; + value = powf(10.f, db/10.f); + break; + } + + case MeterScale: + value = AudioLevel::preview_to_multiplier(lrintf(y), h); + break; + + default: + value = y / h; + } + + return value / m_gain; +} + void SliceLayer::paint(View *v, QPainter &paint, QRect rect) const { @@ -245,21 +324,20 @@ paint.setPen(m_colour); -// int w = (v->width() * 2) / 3; - int xorigin = getVerticalScaleWidth(v, paint) + 1; //!!! (v->width() / 2) - (w / 2); + int xorigin = getVerticalScaleWidth(v, paint) + 1; int w = v->width() - xorigin - 1; m_xorigins[v] = xorigin; // for use in getFeatureDescription int yorigin = v->height() - 20 - paint.fontMetrics().height() - 7; int h = yorigin - paint.fontMetrics().height() - 8; - if (h < 0) return; -// int h = (v->height() * 3) / 4; -// int yorigin = (v->height() / 2) + (h / 2); - + m_yorigins[v] = yorigin; // for getYForValue etc + m_heights[v] = h; + + if (h <= 0) return; + QPainterPath path; - float thresh = -80.f; size_t mh = m_sliceableModel->getHeight(); @@ -276,13 +354,16 @@ size_t f1 = v->getFrameForX(f0x + 1); if (f1 > f0) --f1; - size_t col0 = f0 / m_sliceableModel->getResolution(); + std::cerr << "centre frame " << v->getCentreFrame() << ", x " << f0x << ", f0 " << f0 << ", f1 " << f1 << std::endl; + + size_t res = m_sliceableModel->getResolution(); + size_t col0 = f0 / res; size_t col1 = col0; - if (m_samplingMode != NearestSample) { - col1 = f1 / m_sliceableModel->getResolution(); - } - f0 = col0 * m_sliceableModel->getResolution(); - f1 = (col1 + 1) * m_sliceableModel->getResolution() - 1; + if (m_samplingMode != NearestSample) col1 = f1 / res; + f0 = col0 * res; + f1 = (col1 + 1) * res - 1; + + std::cerr << "resolution " << res << ", col0 " << col0 << ", col1 " << col1 << ", f0 " << f0 << ", f1 " << f1 << std::endl; m_currentf0 = f0; m_currentf1 = f1; @@ -326,34 +407,8 @@ nx = xorigin + getXForBin(bin + 1, mh, w); float value = m_values[bin]; - - value *= m_gain; float norm = 0.f; - float y = 0.f; - - switch (m_energyScale) { - - case dBScale: - { - float db = thresh; - if (value > 0.f) db = 10.f * log10f(value); - if (db < thresh) db = thresh; - norm = (db - thresh) / -thresh; - y = yorigin - (float(h) * norm); - break; - } - - case MeterScale: - y = AudioLevel::multiplier_to_preview(value, h); - norm = float(y) / float(h); - y = yorigin - y; - break; - - default: - norm = value; - y = yorigin - (float(h) * value); - break; - } + float y = getYForValue(value, v, norm); if (m_plotStyle == PlotLines) { diff -r e954c00cbe55 -r b9380f679f70 layer/SliceLayer.h --- a/layer/SliceLayer.h Fri Jun 29 16:50:59 2007 +0000 +++ b/layer/SliceLayer.h Mon Jul 02 13:04:17 2007 +0000 @@ -107,6 +107,9 @@ protected: virtual float getXForBin(int bin, int totalBins, float w) const; virtual int getBinForX(float x, int totalBins, float w) const; + + virtual float getYForValue(float value, const View *v, float &norm) const; + virtual float getValueForY(float y, const View *v) const; virtual QString getFeatureDescription(View *v, QPoint &, bool includeBinDescription, @@ -130,6 +133,8 @@ float m_gain; mutable std::vector m_scalePoints; mutable std::map m_xorigins; + mutable std::map m_yorigins; + mutable std::map m_heights; mutable size_t m_currentf0; mutable size_t m_currentf1; mutable std::vector m_values; diff -r e954c00cbe55 -r b9380f679f70 layer/SpectrumLayer.cpp --- a/layer/SpectrumLayer.cpp Fri Jun 29 16:50:59 2007 +0000 +++ b/layer/SpectrumLayer.cpp Mon Jul 02 13:04:17 2007 +0000 @@ -324,7 +324,8 @@ break; case InvertedLogBins: - x = (w - log10f(maxfreq - freq) * w) / log10f(maxfreq); + if (maxfreq == freq) x = w; + else x = w - (log10f(maxfreq - freq) * w) / log10f(maxfreq); break; } @@ -343,6 +344,40 @@ } bool +SpectrumLayer::getYScaleValue(const View *v, int y, + float &value, QString &unit) const +{ + value = getValueForY(y, v); + + if (m_energyScale == dBScale || m_energyScale == MeterScale) { + + float thresh = -80.f; + + if (value > 0.f) { + value = 10.f * log10f(value); + if (value < thresh) value = thresh; + } else value = thresh; + + unit = "dBV"; + + } else { + unit = "V"; + } + + return true; +} + +bool +SpectrumLayer::getYScaleDifference(const View *v, int y0, int y1, + float &diff, QString &unit) const +{ + bool rv = SliceLayer::getYScaleDifference(v, y0, y1, diff, unit); + if (rv && (unit == "dBV")) unit = "dB"; + return rv; +} + + +bool SpectrumLayer::getCrosshairExtents(View *v, QPainter &paint, QPoint cursorPos, std::vector &extents) const diff -r e954c00cbe55 -r b9380f679f70 layer/SpectrumLayer.h --- a/layer/SpectrumLayer.h Fri Jun 29 16:50:59 2007 +0000 +++ b/layer/SpectrumLayer.h Mon Jul 02 13:04:17 2007 +0000 @@ -62,6 +62,12 @@ virtual bool getXScaleValue(const View *v, int x, float &value, QString &unit) const; + virtual bool getYScaleValue(const View *, int y, + float &value, QString &unit) const; + + virtual bool getYScaleDifference(const View *, int y0, int y1, + float &diff, QString &unit) const; + virtual bool isLayerScrollable(const View *) const { return false; } void setChannel(int); diff -r e954c00cbe55 -r b9380f679f70 layer/WaveformLayer.cpp --- a/layer/WaveformLayer.cpp Fri Jun 29 16:50:59 2007 +0000 +++ b/layer/WaveformLayer.cpp Mon Jul 02 13:04:17 2007 +0000 @@ -637,14 +637,14 @@ if (val < -1.0 || val > 1.0) continue; - int y = getYForValue(v, m_scale, val, ch, minChannel, maxChannel); + int y = getYForValue(v, val, ch); 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); + ny = getYForValue(v, nval, ch); } paint->drawLine(x0, y, x1, y); @@ -995,26 +995,29 @@ } int -WaveformLayer::getYForValue(const View *v, Scale scale, float value, size_t channel, - size_t minChannel, size_t maxChannel) const +WaveformLayer::getYForValue(const View *v, float value, size_t channel) const { + size_t channels = 0, minChannel = 0, maxChannel = 0; + bool mergingChannels = false, mixingChannels = false; + + channels = getChannelArrangement(minChannel, maxChannel, + mergingChannels, mixingChannels); + if (maxChannel < minChannel || channel < minChannel) return 0; 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 my = m + (((channel - minChannel) * h) / channels); + int vy = 0; - switch (scale) { + switch (m_scale) { case LinearScale: vy = int(m * value); @@ -1033,40 +1036,33 @@ } float -WaveformLayer::getValueForY(const View *v, Scale scale, int y, - size_t minChannel, size_t maxChannel) const +WaveformLayer::getValueForY(const View *v, int y, size_t &channel) const { + size_t channels = 0, minChannel = 0, maxChannel = 0; + bool mergingChannels = false, mixingChannels = false; + + channels = getChannelArrangement(minChannel, maxChannel, + mergingChannels, mixingChannels); + if (maxChannel < minChannel) return 0; int h = v->height(); - - int channels = maxChannel - minChannel + 1; int m = (h / channels) / 2; if ((m_scale == dBScale || m_scale == MeterScale) && m_channelMode != MergeChannels) { m = (h / channels); } - - int channel = minChannel; - int mind = 0; + + channel = (y * channels) / h + minChannel; - for (int c = minChannel; c <= maxChannel; ++c) { - int my = m + (((c - minChannel) * h) / channels); - int d = y - my; - if (d < 0) d = -d; - if (c == minChannel || d < mind) { - mind = d; - channel = c; - } - } - int my = m + (((channel - minChannel) * h) / channels); int vy = my - y; float value = 0; + float thresh = -50.f; - switch (scale) { + switch (m_scale) { case LinearScale: value = float(vy) / m; @@ -1077,27 +1073,75 @@ break; case dBScale: - value = AudioLevel::dB_to_multiplier((50 * float(vy)) / m - 50); + value = (-thresh * float(vy)) / m + thresh; + value = AudioLevel::dB_to_multiplier(value); break; } - return value; + return value / m_gain; } bool WaveformLayer::getYScaleValue(const View *v, int y, float &value, QString &unit) const { - size_t channels = 0, minChannel = 0, maxChannel = 0; - bool mergingChannels = false, mixingChannels = false; + size_t channel; - channels = getChannelArrangement(minChannel, maxChannel, - mergingChannels, mixingChannels); + value = getValueForY(v, y, channel); - if (channels == 0) return false; + if (m_scale == dBScale || m_scale == MeterScale) { - value = getValueForY(v, m_scale, y, minChannel, maxChannel); - unit = "V"; + float thresh = -50.f; + + if (value > 0.f) { + value = 10.f * log10f(value); + if (value < thresh) value = thresh; + } else value = thresh; + + unit = "dBV"; + + } else { + unit = "V"; + } + + return true; +} + +bool +WaveformLayer::getYScaleDifference(const View *v, int y0, int y1, + float &diff, QString &unit) const +{ + size_t c0, c1; + float v0 = getValueForY(v, y0, c0); + float v1 = getValueForY(v, y1, c1); + + if (c0 != c1) { + // different channels, not comparable + diff = 0.f; + unit = ""; + return false; + } + + if (m_scale == dBScale || m_scale == MeterScale) { + + float thresh = -50.f; + + if (v1 == v0) diff = thresh; + else { + if (v1 > v0) diff = v0 / v1; + else diff = v1 / v0; + + diff = 10.f * log10f(diff); + if (diff < thresh) diff = thresh; + } + + unit = "dBV"; + + } else { + diff = fabsf(v1 - v0); + unit = "V"; + } + return true; } @@ -1180,11 +1224,11 @@ if (val < -1.0 || val > 1.0) continue; - int y = getYForValue(v, m_scale, val, ch, minChannel, maxChannel); + int y = getYForValue(v, val, ch); int ny = y; if (nval != 0.0) { - ny = getYForValue(v, m_scale, nval, ch, minChannel, maxChannel); + ny = getYForValue(v, nval, ch); } bool spaceForLabel = (i == 0 || diff -r e954c00cbe55 -r b9380f679f70 layer/WaveformLayer.h --- a/layer/WaveformLayer.h Fri Jun 29 16:50:59 2007 +0000 +++ b/layer/WaveformLayer.h Mon Jul 02 13:04:17 2007 +0000 @@ -181,6 +181,9 @@ virtual bool getYScaleValue(const View *v, int y, float &value, QString &unit) const; + + virtual bool getYScaleDifference(const View *v, int y0, int y1, + float &diff, QString &unit) const; virtual QString toXmlString(QString indent = "", QString extraAttributes = "") const; @@ -200,11 +203,9 @@ size_t getChannelArrangement(size_t &min, size_t &max, bool &merging, bool &mixing) const; - int getYForValue(const View *v, Scale scale, float value, size_t channel, - size_t minChannel, size_t maxChannel) const; + int getYForValue(const View *v, float value, size_t channel) const; - float getValueForY(const View *v, Scale scale, int y, - size_t minChannel, size_t maxChannel) const; + float getValueForY(const View *v, int y, size_t &channel) const; float m_gain; bool m_autoNormalize; diff -r e954c00cbe55 -r b9380f679f70 layer/layer.pro --- a/layer/layer.pro Fri Jun 29 16:50:59 2007 +0000 +++ b/layer/layer.pro Mon Jul 02 13:04:17 2007 +0000 @@ -20,10 +20,10 @@ LayerFactory.h \ NoteLayer.h \ PaintAssistant.h \ + SliceableLayer.h \ + SliceLayer.h \ SpectrogramLayer.h \ SpectrumLayer.h \ - SliceLayer.h \ - SliceableLayer.h \ TextLayer.h \ TimeInstantLayer.h \ TimeRulerLayer.h \ @@ -35,9 +35,9 @@ LayerFactory.cpp \ NoteLayer.cpp \ PaintAssistant.cpp \ + SliceLayer.cpp \ SpectrogramLayer.cpp \ SpectrumLayer.cpp \ - SliceLayer.cpp \ TextLayer.cpp \ TimeInstantLayer.cpp \ TimeRulerLayer.cpp \ diff -r e954c00cbe55 -r b9380f679f70 view/Overview.cpp --- a/view/Overview.cpp Fri Jun 29 16:50:59 2007 +0000 +++ b/view/Overview.cpp Mon Jul 02 13:04:17 2007 +0000 @@ -33,6 +33,7 @@ m_followPan = false; m_followZoom = false; setPlaybackFollow(PlaybackIgnore); + m_modelTestTime.start(); } void @@ -50,13 +51,17 @@ } if (!zoomChanged) { - for (LayerList::const_iterator i = m_layers.begin(); - i != m_layers.end(); ++i) { - if ((*i)->getModel() && - !(*i)->getModel()->isOK() || - !(*i)->getModel()->isReady()) { - return; + if (m_modelTestTime.elapsed() < 1000) { + for (LayerList::const_iterator i = m_layers.begin(); + i != m_layers.end(); ++i) { + if ((*i)->getModel() && + !(*i)->getModel()->isOK() || + !(*i)->getModel()->isReady()) { + return; + } } + } else { + m_modelTestTime.restart(); } } diff -r e954c00cbe55 -r b9380f679f70 view/Overview.h --- a/view/Overview.h Fri Jun 29 16:50:59 2007 +0000 +++ b/view/Overview.h Mon Jul 02 13:04:17 2007 +0000 @@ -19,6 +19,7 @@ #include "View.h" #include +#include class QWidget; class QPaintEvent; @@ -62,6 +63,7 @@ QPoint m_mousePos; bool m_clickedInRange; size_t m_dragCentreFrame; + QTime m_modelTestTime; typedef std::set ViewSet; ViewSet m_views; diff -r e954c00cbe55 -r b9380f679f70 view/Pane.cpp --- a/view/Pane.cpp Fri Jun 29 16:50:59 2007 +0000 +++ b/view/Pane.cpp Mon Jul 02 13:04:17 2007 +0000 @@ -631,7 +631,7 @@ c = QColor(240, 240, 240); } paint.setPen(c); - int x = width() / 2 + 1; + int x = width() / 2; paint.drawLine(x, 0, x, height() - 1); paint.drawLine(x-1, 1, x+1, 1); paint.drawLine(x-2, 0, x+2, 0); diff -r e954c00cbe55 -r b9380f679f70 view/View.cpp --- a/view/View.cpp Fri Jun 29 16:50:59 2007 +0000 +++ b/view/View.cpp Mon Jul 02 13:04:17 2007 +0000 @@ -1726,9 +1726,18 @@ bw = std::max(bw, paint.fontMetrics().width(bys)); } } - - if (b0 && b1 && u0 == u1) { - dys = QString("(%1 %2)").arg(fabs(v1 - v0)).arg(u1); + + bool bd = false; + float dy = 0.f; + QString du; + + if ((bd = topLayer->getYScaleDifference(this, r.y(), r.y() + r.height(), + dy, du))) { + if (du != "") { + dys = QString("(%1 %2)").arg(dy).arg(du); + } else { + dys = QString("(%1)").arg(dy); + } dw = std::max(dw, paint.fontMetrics().width(dys)); }