Mercurial > hg > svgui
diff layer/SpectrumLayer.cpp @ 153:aaa3a53dbb10
* Some work on SpectrumLayer properties etc
author | Chris Cannam |
---|---|
date | Wed, 27 Sep 2006 14:56:31 +0000 |
parents | 9e6b3e239b9d |
children | 53b9c7656798 |
line wrap: on
line diff
--- 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