Mercurial > hg > svgui
changeset 153:aaa3a53dbb10
* Some work on SpectrumLayer properties etc
author | Chris Cannam |
---|---|
date | Wed, 27 Sep 2006 14:56:31 +0000 |
parents | 6a3f3c13173f |
children | 30d624900564 |
files | layer/SpectrogramLayer.cpp layer/SpectrumLayer.cpp layer/SpectrumLayer.h view/View.cpp |
diffstat | 4 files changed, 548 insertions(+), 81 deletions(-) [+] |
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp Mon Sep 25 12:05:41 2006 +0000 +++ b/layer/SpectrogramLayer.cpp Wed Sep 27 14:56:31 2006 +0000 @@ -131,7 +131,6 @@ PropertyList list; list.push_back("Colour"); list.push_back("Colour Scale"); -// list.push_back("Window Type"); list.push_back("Window Size"); list.push_back("Window Increment"); list.push_back("Normalize Columns"); @@ -140,10 +139,10 @@ list.push_back("Threshold"); list.push_back("Gain"); list.push_back("Colour Rotation"); - list.push_back("Min Frequency"); - list.push_back("Max Frequency"); +// list.push_back("Min Frequency"); +// list.push_back("Max Frequency"); list.push_back("Frequency Scale"); -// list.push_back("Zero Padding"); +//// list.push_back("Zero Padding"); return list; } @@ -152,7 +151,6 @@ { if (name == "Colour") return tr("Colour"); if (name == "Colour Scale") return tr("Colour Scale"); - if (name == "Window Type") return tr("Window Type"); if (name == "Window Size") return tr("Window Size"); if (name == "Window Increment") return tr("Window Overlap"); if (name == "Normalize Columns") return tr("Normalize Columns"); @@ -183,22 +181,24 @@ QString SpectrogramLayer::getPropertyGroupName(const PropertyName &name) const { + if (name == "Bin Display" || + name == "Frequency Scale") return tr("Bins"); if (name == "Window Size" || - name == "Window Type" || name == "Window Increment" || name == "Zero Padding") return tr("Window"); if (name == "Colour" || - name == "Gain" || +// name == "Gain" || name == "Threshold" || name == "Colour Rotation") return tr("Colour"); if (name == "Normalize Columns" || name == "Normalize Visible Area" || - name == "Bin Display" || +// name == "Bin Display" || + name == "Gain" || name == "Colour Scale") return tr("Scale"); - if (name == "Max Frequency" || - name == "Min Frequency" || - name == "Frequency Scale" || - name == "Frequency Adjustment") return tr("Range"); +// if (name == "Max Frequency" || +// name == "Min Frequency" || +// name == "Frequency Scale" || +// name == "Frequency Adjustment") return tr("Range"); return QString(); } @@ -251,13 +251,6 @@ deft = (int)m_colourScheme; - } else if (name == "Window Type") { - - *min = 0; - *max = 6; - - deft = (int)m_windowType; - } else if (name == "Window Size") { *min = 0; @@ -370,18 +363,6 @@ case 4: return tr("Phase"); } } - if (name == "Window Type") { - switch ((WindowType)value) { - default: - case RectangularWindow: return tr("Rectangle"); - case BartlettWindow: return tr("Bartlett"); - case HammingWindow: return tr("Hamming"); - case HanningWindow: return tr("Hanning"); - case BlackmanWindow: return tr("Blackman"); - case GaussianWindow: return tr("Gaussian"); - case ParzenWindow: return tr("Parzen"); - } - } if (name == "Window Size") { return QString("%1").arg(32 << value); } @@ -469,8 +450,6 @@ case 5: setColourScheme(BlueOnBlack); break; case 6: setColourScheme(Rainbow); break; } - } else if (name == "Window Type") { - setWindowType(WindowType(value)); } else if (name == "Window Size") { setWindowSize(32 << value); } else if (name == "Window Increment") { @@ -1231,6 +1210,8 @@ float SpectrogramLayer::getInputForDisplayValue(unsigned char uc) const { + //!!! unused + int value = uc; float input; @@ -1592,13 +1573,13 @@ if (m_fftModels.find(v) == m_fftModels.end()) { m_fftModels[v] = FFTFillPair (new FFTModel(m_model, - m_channel, - m_windowType, - m_windowSize, - getWindowIncrement(), - fftSize, - true, - m_candidateFillStartFrame), + m_channel, + m_windowType, + m_windowSize, + getWindowIncrement(), + fftSize, + true, + m_candidateFillStartFrame), 0); delete m_updateTimer; @@ -2876,13 +2857,11 @@ s += QString("channel=\"%1\" " "windowSize=\"%2\" " - "windowType=\"%3\" " - "windowHopLevel=\"%4\" " - "gain=\"%5\" " - "threshold=\"%6\" ") + "windowHopLevel=\"%3\" " + "gain=\"%4\" " + "threshold=\"%5\" ") .arg(m_channel) .arg(m_windowSize) - .arg(m_windowType) .arg(m_windowHopLevel) .arg(m_gain) .arg(m_threshold); @@ -2894,7 +2873,8 @@ "colourRotation=\"%5\" " "frequencyScale=\"%6\" " "binDisplay=\"%7\" " - "normalizeColumns=\"%8\"") + "normalizeColumns=\"%8\" " + "normalizeVisibleArea=\"%9\"") .arg(m_minFrequency) .arg(m_maxFrequency) .arg(m_colourScale) @@ -2902,7 +2882,8 @@ .arg(m_colourRotation) .arg(m_frequencyScale) .arg(m_binDisplay) - .arg(m_normalizeColumns ? "true" : "false"); + .arg(m_normalizeColumns ? "true" : "false") + .arg(m_normalizeVisibleArea ? "true" : "false"); return Layer::toXmlString(indent, extraAttributes + " " + s); } @@ -2918,10 +2899,6 @@ size_t windowSize = attributes.value("windowSize").toUInt(&ok); if (ok) setWindowSize(windowSize); - WindowType windowType = (WindowType) - attributes.value("windowType").toInt(&ok); - if (ok) setWindowType(windowType); - size_t windowHopLevel = attributes.value("windowHopLevel").toUInt(&ok); if (ok) setWindowHopLevel(windowHopLevel); else { @@ -2970,5 +2947,9 @@ bool normalizeColumns = (attributes.value("normalizeColumns").trimmed() == "true"); setNormalizeColumns(normalizeColumns); + + bool normalizeVisibleArea = + (attributes.value("normalizeVisibleArea").trimmed() == "true"); + setNormalizeVisibleArea(normalizeVisibleArea); }
--- a/layer/SpectrumLayer.cpp Mon Sep 25 12:05:41 2006 +0000 +++ b/layer/SpectrumLayer.cpp Wed Sep 27 14:56:31 2006 +0000 @@ -18,45 +18,106 @@ #include "data/model/FFTModel.h" #include "view/View.h" +#include "base/AudioLevel.h" +#include "base/Preferences.h" #include <QPainter> #include <QPainterPath> SpectrumLayer::SpectrumLayer() : m_model(0), - m_fft(0), - m_colour(Qt::blue) + m_channelMode(MixChannels), + m_channel(-1), + m_channelSet(false), + m_colour(Qt::darkBlue), + m_energyScale(dBScale), + m_normalize(false), + m_gain(1.0), + m_windowSize(1024), + m_windowType(HanningWindow), + m_windowHopLevel(2) { + Preferences *prefs = Preferences::getInstance(); + connect(prefs, SIGNAL(propertyChanged(PropertyContainer::PropertyName)), + this, SLOT(preferenceChanged(PropertyContainer::PropertyName))); + setWindowType(prefs->getWindowType()); } SpectrumLayer::~SpectrumLayer() { - delete m_fft; + for (size_t i = 0; i < m_fft.size(); ++i) delete m_fft[i]; } void SpectrumLayer::setModel(DenseTimeValueModel *model) { m_model = model; - delete m_fft; - m_fft = new FFTModel(m_model, - -1, - HanningWindow, - 1024, - 256, - 1024, - true); - m_fft->resume(); + setupFFTs(); +} + +void +SpectrumLayer::setupFFTs() +{ + for (size_t i = 0; i < m_fft.size(); ++i) delete m_fft[i]; + m_fft.clear(); + + int minChannel = m_channel, maxChannel = m_channel; + + if (m_channel == -1 && + m_channelMode != MixChannels) { + minChannel = 0; + maxChannel = 0; + if (m_model->getChannelCount() > 1) { + maxChannel = m_model->getChannelCount() - 1; + } + } + + for (int c = minChannel; c <= maxChannel; ++c) { + + m_fft.push_back(new FFTModel(m_model, + c, + HanningWindow, + m_windowSize, + getWindowIncrement(), + m_windowSize, + true)); + + if (m_channelSet) m_fft[m_fft.size()-1]->resume(); + } +} + +void +SpectrumLayer::setChannel(int channel) +{ + m_channelSet = true; + + if (m_channel == channel) { + for (size_t i = 0; i < m_fft.size(); ++i) { + m_fft[i]->resume(); + } + return; + } + + m_channel = channel; + + if (!m_fft.empty()) setupFFTs(); + + emit layerParametersChanged(); } void SpectrumLayer::paint(View *v, QPainter &paint, QRect rect) const { - if (!m_fft) return; + if (m_fft.empty()) return; + if (!m_channelSet) { + for (size_t i = 0; i < m_fft.size(); ++i) { + m_fft[i]->resume(); + } + } - int fftSize = 1024; //!!! ... - int windowIncrement = 256; - int windowSize = 1024; + FFTModel *fft = m_fft[0]; //!!! for now + + int windowIncrement = getWindowIncrement(); size_t f = v->getCentreFrame(); @@ -75,15 +136,38 @@ QPainterPath path; float thresh = -80.f; - for (size_t bin = 0; bin < m_fft->getHeight(); ++bin) { + for (size_t bin = 0; bin < fft->getHeight(); ++bin) { - float mag = m_fft->getMagnitudeAt(column, bin); - float db = thresh; - if (mag > 0.f) db = 10.f * log10f(mag); - if (db < thresh) db = thresh; - float val = (db - thresh) / -thresh; - float x = xorigin + (float(w) * bin) / m_fft->getHeight(); - float y = yorigin - (float(h) * val); + float x = xorigin + (float(w) * bin) / fft->getHeight(); + float mag; + if (m_normalize) { + mag = fft->getNormalizedMagnitudeAt(column, bin); + } else { + mag = fft->getMagnitudeAt(column, bin); + } + mag *= m_gain; + float y = 0.f; + + switch (m_energyScale) { + + case dBScale: + { + float db = thresh; + if (mag > 0.f) db = 10.f * log10f(mag); + if (db < thresh) db = thresh; + float val = (db - thresh) / -thresh; + y = yorigin - (float(h) * val); + break; + } + + case MeterScale: + y = yorigin - AudioLevel::multiplier_to_preview(mag, h); + break; + + default: + y = yorigin - (float(h) * mag); + break; + } if (bin == 0) { path.moveTo(x, y); @@ -93,14 +177,352 @@ } paint.drawPath(path); -// paint.setRenderHint(QPainter::Antialiasing, false); paint.restore(); } +Layer::PropertyList +SpectrumLayer::getProperties() const +{ + PropertyList list; + list.push_back("Colour"); + list.push_back("Scale"); + list.push_back("Normalize"); + list.push_back("Gain"); + list.push_back("Window Size"); + list.push_back("Window Increment"); + + if (m_model && m_model->getChannelCount() > 1 && m_channel == -1) { + list.push_back("Channels"); + } + + return list; +} + +QString +SpectrumLayer::getPropertyLabel(const PropertyName &name) const +{ + if (name == "Colour") return tr("Colour"); + if (name == "Energy Scale") return tr("Scale"); + if (name == "Channels") return tr("Channels"); + if (name == "Window Size") return tr("Window Size"); + if (name == "Window Increment") return tr("Window Overlap"); + if (name == "Normalize") return tr("Normalize"); + if (name == "Gain") return tr("Gain"); + return ""; +} + +Layer::PropertyType +SpectrumLayer::getPropertyType(const PropertyName &name) const +{ + if (name == "Gain") return RangeProperty; + if (name == "Normalize") return ToggleProperty; + return ValueProperty; +} + +QString +SpectrumLayer::getPropertyGroupName(const PropertyName &name) const +{ + if (name == "Window Size" || + name == "Window Increment") return tr("Window"); + if (name == "Scale" || + name == "Normalize" || + name == "Gain") return tr("Energy Scale"); + return QString(); +} + +int +SpectrumLayer::getPropertyRangeAndValue(const PropertyName &name, + int *min, int *max) const +{ + int deft = 0; + + int garbage0, garbage1; + if (!min) min = &garbage0; + if (!max) max = &garbage1; + + if (name == "Gain") { + + *min = -50; + *max = 50; + + deft = lrint(log10(m_gain) * 20.0); + if (deft < *min) deft = *min; + if (deft > *max) deft = *max; + + } else if (name == "Normalize") { + + deft = (m_normalize ? 1 : 0); + + } else if (name == "Colour") { + + *min = 0; + *max = 5; + + if (m_colour == Qt::black) deft = 0; + else if (m_colour == Qt::darkRed) deft = 1; + else if (m_colour == Qt::darkBlue) deft = 2; + else if (m_colour == Qt::darkGreen) deft = 3; + else if (m_colour == QColor(200, 50, 255)) deft = 4; + else if (m_colour == QColor(255, 150, 50)) deft = 5; + + } else if (name == "Channels") { + + *min = 0; + *max = 2; + if (m_channelMode == MixChannels) deft = 1; + else if (m_channelMode == OverlayChannels) deft = 2; + else deft = 0; + + } else if (name == "Scale") { + + *min = 0; + *max = 2; + + deft = (int)m_energyScale; + + } else if (name == "Window Size") { + + *min = 0; + *max = 10; + + deft = 0; + int ws = m_windowSize; + while (ws > 32) { ws >>= 1; deft ++; } + + } else if (name == "Window Increment") { + + *min = 0; + *max = 5; + + deft = m_windowHopLevel; + + } else { + deft = Layer::getPropertyRangeAndValue(name, min, max); + } + + return deft; +} + +QString +SpectrumLayer::getPropertyValueLabel(const PropertyName &name, + int value) const +{ + if (name == "Colour") { + switch (value) { + default: + case 0: return tr("Black"); + case 1: return tr("Red"); + case 2: return tr("Blue"); + case 3: return tr("Green"); + case 4: return tr("Purple"); + case 5: return tr("Orange"); + } + } + if (name == "Scale") { + switch (value) { + default: + case 0: return tr("Linear"); + case 1: return tr("Meter"); + case 2: return tr("dB"); + } + } + if (name == "Channels") { + switch (value) { + default: + case 0: return tr("Separate"); + case 1: return tr("Mean"); + case 2: return tr("Overlay"); + } + } + if (name == "Window Size") { + return QString("%1").arg(32 << value); + } + if (name == "Window Increment") { + switch (value) { + default: + case 0: return tr("None"); + case 1: return tr("25 %"); + case 2: return tr("50 %"); + case 3: return tr("75 %"); + case 4: return tr("87.5 %"); + case 5: return tr("93.75 %"); + } + } + return tr("<unknown>"); +} + void -SpectrumLayer::setProperties(const QXmlAttributes &attr) +SpectrumLayer::setProperty(const PropertyName &name, int value) { + if (name == "Gain") { + setGain(pow(10, float(value)/20.0)); + } else if (name == "Colour") { + switch (value) { + default: + case 0: setBaseColour(Qt::black); break; + case 1: setBaseColour(Qt::darkRed); break; + case 2: setBaseColour(Qt::darkBlue); break; + case 3: setBaseColour(Qt::darkGreen); break; + case 4: setBaseColour(QColor(200, 50, 255)); break; + case 5: setBaseColour(QColor(255, 150, 50)); break; + } + } else if (name == "Channels") { + if (value == 1) setChannelMode(MixChannels); + else if (value == 2) setChannelMode(OverlayChannels); + else setChannelMode(SeparateChannels); + } else if (name == "Scale") { + switch (value) { + default: + case 0: setEnergyScale(LinearScale); break; + case 1: setEnergyScale(MeterScale); break; + case 2: setEnergyScale(dBScale); break; + } + } else if (name == "Window Size") { + setWindowSize(32 << value); + } else if (name == "Window Increment") { + setWindowHopLevel(value); + } else if (name == "Normalize") { + setNormalize(value ? true : false); + } +} + +void +SpectrumLayer::setBaseColour(QColor colour) +{ + if (m_colour == colour) return; + m_colour = colour; + emit layerParametersChanged(); +} + +void +SpectrumLayer::setChannelMode(ChannelMode channelMode) +{ + if (m_channelMode == channelMode) return; + m_channelMode = channelMode; + emit layerParametersChanged(); +} + +void +SpectrumLayer::setEnergyScale(EnergyScale scale) +{ + if (m_energyScale == scale) return; + m_energyScale = scale; + emit layerParametersChanged(); +} + +void +SpectrumLayer::setWindowSize(size_t ws) +{ + if (m_windowSize == ws) return; + m_windowSize = ws; + setupFFTs(); + emit layerParametersChanged(); +} + +void +SpectrumLayer::setWindowHopLevel(size_t v) +{ + if (m_windowHopLevel == v) return; + m_windowHopLevel = v; + setupFFTs(); + emit layerParametersChanged(); +} + +void +SpectrumLayer::setWindowType(WindowType w) +{ + if (m_windowType == w) return; + m_windowType = w; + setupFFTs(); + emit layerParametersChanged(); +} + +void +SpectrumLayer::setNormalize(bool n) +{ + if (m_normalize == n) return; + m_normalize = n; + emit layerParametersChanged(); +} + +void +SpectrumLayer::setGain(float gain) +{ + if (m_gain == gain) return; + m_gain = gain; + emit layerParametersChanged(); +} + +void +SpectrumLayer::preferenceChanged(PropertyContainer::PropertyName name) +{ + if (name == "Window Type") { + setWindowType(Preferences::getInstance()->getWindowType()); + return; + } +} + +QString +SpectrumLayer::toXmlString(QString indent, QString extraAttributes) const +{ + QString s; + + s += QString("colour=\"%1\" " + "channelMode=\"%2\" " + "channel=\"%3\" " + "energyScale=\"%4\" " + "windowSize=\"%5\" " + "windowHopLevel=\"%6\" " + "gain=\"%7\" " + "normalize=\"%8\"") + .arg(encodeColour(m_colour)) + .arg(m_channelMode) + .arg(m_channel) + .arg(m_energyScale) + .arg(m_windowSize) + .arg(m_windowHopLevel) + .arg(m_gain) + .arg(m_normalize ? "true" : "false"); + + return Layer::toXmlString(indent, extraAttributes + " " + s); +} + +void +SpectrumLayer::setProperties(const QXmlAttributes &attributes) +{ + bool ok = false; + + QString colourSpec = attributes.value("colour"); + if (colourSpec != "") { + QColor colour(colourSpec); + if (colour.isValid()) { + setBaseColour(QColor(colourSpec)); + } + } + + ChannelMode channelMode = (ChannelMode) + attributes.value("channelMode").toInt(&ok); + if (ok) setChannelMode(channelMode); + + int channel = attributes.value("channel").toInt(&ok); + if (ok) setChannel(channel); + + EnergyScale scale = (EnergyScale) + attributes.value("energyScale").toInt(&ok); + if (ok) setEnergyScale(scale); + + size_t windowSize = attributes.value("windowSize").toUInt(&ok); + if (ok) setWindowSize(windowSize); + + size_t windowHopLevel = attributes.value("windowHopLevel").toUInt(&ok); + if (ok) setWindowHopLevel(windowHopLevel); + + float gain = attributes.value("gain").toFloat(&ok); + if (ok) setGain(gain); + + bool normalize = (attributes.value("normalize").trimmed() == "true"); + setNormalize(normalize); } bool
--- a/layer/SpectrumLayer.h Mon Sep 25 12:05:41 2006 +0000 +++ b/layer/SpectrumLayer.h Wed Sep 27 14:56:31 2006 +0000 @@ -19,6 +19,8 @@ #include "Layer.h" +#include "base/Window.h" + #include "data/model/DenseTimeValueModel.h" #include <QColor> @@ -37,6 +39,15 @@ virtual const Model *getModel() const { return m_model; } virtual void paint(View *v, QPainter &paint, QRect rect) const; + virtual PropertyList getProperties() const; + virtual QString getPropertyLabel(const PropertyName &) const; + virtual PropertyType getPropertyType(const PropertyName &) const; + virtual QString getPropertyGroupName(const PropertyName &) const; + virtual int getPropertyRangeAndValue(const PropertyName &, + int *min, int *max) const; + virtual QString getPropertyValueLabel(const PropertyName &, + int value) const; + virtual void setProperty(const PropertyName &, int value); virtual void setProperties(const QXmlAttributes &); virtual bool getValueExtents(float &min, float &max, @@ -44,12 +55,64 @@ virtual bool isLayerScrollable(const View *v) const { return false; } - virtual QString getPropertyLabel(const PropertyName &) const { return ""; } + enum ChannelMode { SeparateChannels, MixChannels, OverlayChannels }; + + void setChannelMode(ChannelMode); + ChannelMode getChannelCount() const { return m_channelMode; } + + void setChannel(int); + int getChannel() const { return m_channel; } + + enum EnergyScale { LinearScale, MeterScale, dBScale }; + + void setBaseColour(QColor); + QColor getBaseColour() const { return m_colour; } + + void setEnergyScale(EnergyScale); + EnergyScale getEnergyScale() const { return m_energyScale; } + + void setWindowSize(size_t); + size_t getWindowSize() const { return m_windowSize; } + + void setWindowHopLevel(size_t level); + size_t getWindowHopLevel() const { return m_windowHopLevel; } + + void setWindowType(WindowType type); + WindowType getWindowType() const { return m_windowType; } + + void setGain(float gain); + float getGain() const; + + void setNormalize(bool n); + bool getNormalize() const; + + virtual QString toXmlString(QString indent = "", + QString extraAttributes = "") const; + +protected slots: + void preferenceChanged(PropertyContainer::PropertyName name); protected: - DenseTimeValueModel *m_model; - FFTModel *m_fft; - QColor m_colour; + DenseTimeValueModel *m_model; + std::vector<FFTModel *> m_fft; + ChannelMode m_channelMode; + int m_channel; + bool m_channelSet; + QColor m_colour; + EnergyScale m_energyScale; + bool m_normalize; + float m_gain; + size_t m_windowSize; + WindowType m_windowType; + size_t m_windowHopLevel; + + void setupFFTs(); + + size_t getWindowIncrement() const { + if (m_windowHopLevel == 0) return m_windowSize; + else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4; + else return m_windowSize / (1 << (m_windowHopLevel - 1)); + } }; #endif