Chris@58: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@59: Sonic Visualiser Chris@59: An audio file viewer and annotation editor. Chris@59: Centre for Digital Music, Queen Mary, University of London. Chris@182: This file copyright 2006 Chris Cannam and QMUL. Chris@0: Chris@59: This program is free software; you can redistribute it and/or Chris@59: modify it under the terms of the GNU General Public License as Chris@59: published by the Free Software Foundation; either version 2 of the Chris@59: License, or (at your option) any later version. See the file Chris@59: COPYING included with this distribution for more information. Chris@0: */ Chris@0: Chris@1030: #ifndef SPECTROGRAM_LAYER_H Chris@1030: #define SPECTROGRAM_LAYER_H Chris@0: Chris@193: #include "SliceableLayer.h" Chris@0: #include "base/Window.h" Chris@1058: #include "base/MagnitudeRange.h" Chris@71: #include "base/RealTime.h" Chris@92: #include "base/Thread.h" Chris@122: #include "base/PropertyContainer.h" Chris@128: #include "data/model/PowerOfSqrtTwoZoomConstraint.h" Chris@128: #include "data/model/DenseTimeValueModel.h" Chris@130: #include "data/model/FFTModel.h" Chris@0: Chris@1085: #include "VerticalBinLayer.h" Chris@1092: #include "ColourScale.h" Chris@1093: #include "Colour3DPlotRenderer.h" Chris@1030: Chris@0: #include Chris@0: #include Chris@95: #include Chris@95: #include Chris@0: Chris@0: class View; Chris@0: class QPainter; Chris@0: class QImage; Chris@0: class QPixmap; Chris@0: class QTimer; Chris@130: class FFTModel; Chris@484: class Dense3DModelPeakCache; Chris@0: Chris@0: /** Chris@0: * SpectrogramLayer represents waveform data (obtained from a Chris@0: * DenseTimeValueModel) in spectrogram form. Chris@0: */ Chris@0: Chris@1110: class SpectrogramLayer : public VerticalBinLayer, Chris@1266: public PowerOfSqrtTwoZoomConstraint Chris@0: { Chris@0: Q_OBJECT Chris@0: Chris@0: public: Chris@37: enum Configuration { FullRangeDb, MelodicRange, MelodicPeaks }; Chris@0: Chris@44: SpectrogramLayer(Configuration = FullRangeDb); Chris@0: ~SpectrogramLayer(); Chris@0: Chris@1406: const ZoomConstraint *getZoomConstraint() const override { return this; } Chris@1470: ModelId getModel() const override { return m_model; } Chris@1406: void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const override; Chris@1406: void setSynchronousPainting(bool synchronous) override; Chris@0: Chris@1406: int getVerticalScaleWidth(LayerGeometryProvider *v, bool detailed, QPainter &) const override; Chris@1406: void paintVerticalScale(LayerGeometryProvider *v, bool detailed, QPainter &paint, QRect rect) const override; Chris@0: Chris@1406: bool getCrosshairExtents(LayerGeometryProvider *, QPainter &, QPoint cursorPos, Chris@1406: std::vector &extents) const override; Chris@1406: void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const override; Chris@77: Chris@1406: QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const override; Chris@0: Chris@1406: bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, Chris@1266: int &resolution, Chris@1406: SnapType snap) const override; Chris@13: Chris@1406: void measureDoubleClick(LayerGeometryProvider *, QMouseEvent *) override; Chris@283: Chris@1406: bool hasLightBackground() const override; Chris@224: Chris@1470: void setModel(ModelId model); // a DenseTimeValueModel Chris@0: Chris@1406: PropertyList getProperties() const override; Chris@1406: QString getPropertyLabel(const PropertyName &) const override; Chris@1406: QString getPropertyIconName(const PropertyName &) const override; Chris@1406: PropertyType getPropertyType(const PropertyName &) const override; Chris@1406: QString getPropertyGroupName(const PropertyName &) const override; Chris@1406: int getPropertyRangeAndValue(const PropertyName &, Chris@1406: int *min, int *max, int *deflt) const override; Chris@1406: QString getPropertyValueLabel(const PropertyName &, Chris@1406: int value) const override; Chris@1406: QString getPropertyValueIconName(const PropertyName &, Chris@1406: int value) const override; Chris@1406: RangeMapper *getNewPropertyRangeMapper(const PropertyName &) const override; Chris@1406: void setProperty(const PropertyName &, int value) override; Chris@0: Chris@0: /** Chris@0: * Specify the channel to use from the source model. Chris@0: * A value of -1 means to mix all available channels. Chris@0: * The default is channel 0. Chris@0: */ Chris@0: void setChannel(int); Chris@0: int getChannel() const; Chris@0: Chris@805: void setWindowSize(int); Chris@805: int getWindowSize() const; Chris@0: Chris@805: void setWindowHopLevel(int level); Chris@805: int getWindowHopLevel() const; Chris@0: Chris@1379: void setOversampling(int oversampling); Chris@1379: int getOversampling() const; Chris@1379: Chris@0: void setWindowType(WindowType type); Chris@0: WindowType getWindowType() const; Chris@0: Chris@0: /** Chris@110: * Set the gain multiplier for sample values in this view. Chris@0: * The default is 1.0. Chris@0: */ Chris@0: void setGain(float gain); Chris@0: float getGain() const; Chris@0: Chris@37: /** Chris@110: * Set the threshold for sample values to qualify for being shown Chris@110: * in the FFT, in voltage units. Chris@37: * Chris@1127: * The default is 10^-8 (-80dB). Chris@37: */ Chris@37: void setThreshold(float threshold); Chris@37: float getThreshold() const; Chris@37: Chris@805: void setMinFrequency(int); Chris@805: int getMinFrequency() const; Chris@37: Chris@805: void setMaxFrequency(int); // 0 -> no maximum Chris@805: int getMaxFrequency() const; Chris@0: Chris@0: /** Chris@1092: * Specify the scale for sample levels. See ColourScale and Chris@1092: * WaveformLayer for comparison and details of meter and dB Chris@1092: * scaling. The default is LogColourScale. Chris@0: */ Chris@1105: void setColourScale(ColourScaleType); Chris@1105: ColourScaleType getColourScale() const; Chris@0: Chris@0: /** Chris@1137: * Specify multiple factor for colour scale. This is 2.0 for Chris@1137: * log-power spectrogram and 1.0 otherwise. Chris@1137: */ Chris@1137: void setColourScaleMultiple(double); Chris@1137: double getColourScaleMultiple() const; Chris@1137: Chris@1137: /** Chris@0: * Specify the scale for the y axis. Chris@0: */ Chris@1103: void setBinScale(BinScale); Chris@1103: BinScale getBinScale() const; Chris@0: Chris@35: /** Chris@35: * Specify the processing of frequency bins for the y axis. Chris@35: */ Chris@1103: void setBinDisplay(BinDisplay); Chris@1103: BinDisplay getBinDisplay() const; Chris@862: Chris@719: /** Chris@1104: * Specify the normalization mode for individual columns. Chris@719: */ Chris@1104: void setNormalization(ColumnNormalization); Chris@1104: ColumnNormalization getNormalization() const; Chris@1104: Chris@1104: /** Chris@1104: * Specify whether to normalize the visible area. Chris@1104: */ Chris@1104: void setNormalizeVisibleArea(bool); Chris@1104: bool getNormalizeVisibleArea() const; Chris@120: Chris@719: /** Chris@862: * Specify the colour map. See ColourMapper for the colour map Chris@862: * values. Chris@719: */ Chris@197: void setColourMap(int map); Chris@197: int getColourMap() const; Chris@0: Chris@9: /** Chris@9: * Specify the colourmap rotation for the colour scale. Chris@9: */ Chris@9: void setColourRotation(int); Chris@9: int getColourRotation() const; Chris@9: Chris@1406: VerticalPosition getPreferredFrameCountPosition() const override { Chris@1266: return PositionTop; Chris@0: } Chris@0: Chris@1406: bool isLayerOpaque() const override { return true; } Chris@287: Chris@1406: ColourSignificance getLayerColourSignificance() const override { Chris@287: return ColourHasMeaningfulValue; Chris@287: } Chris@15: Chris@918: double getYForFrequency(const LayerGeometryProvider *v, double frequency) const; Chris@918: double getFrequencyForY(const LayerGeometryProvider *v, int y) const; Chris@42: Chris@1085: //!!! VerticalBinLayer methods. Note overlap with get*BinRange() Chris@1406: double getYForBin(const LayerGeometryProvider *, double bin) const override; Chris@1406: double getBinForY(const LayerGeometryProvider *, double y) const override; Chris@1085: Chris@1406: int getCompletion(LayerGeometryProvider *v) const override; Chris@1406: QString getError(LayerGeometryProvider *v) const override; Chris@0: Chris@1406: bool getValueExtents(double &min, double &max, Chris@1406: bool &logarithmic, QString &unit) const override; Chris@101: Chris@1406: bool getDisplayExtents(double &min, double &max) const override; Chris@79: Chris@1406: bool setDisplayExtents(double min, double max) override; Chris@120: Chris@1406: bool getYScaleValue(const LayerGeometryProvider *, int, double &, QString &) const override; Chris@261: Chris@1406: void toXml(QTextStream &stream, QString indent = "", Chris@1406: QString extraAttributes = "") const override; Chris@6: Chris@1406: void setProperties(const QXmlAttributes &attributes) override; Chris@11: Chris@1406: void setLayerDormant(const LayerGeometryProvider *v, bool dormant) override; Chris@29: Chris@1406: bool isLayerScrollable(const LayerGeometryProvider *) const override; Chris@94: Chris@1406: int getVerticalZoomSteps(int &defaultStep) const override; Chris@1406: int getCurrentVerticalZoomStep() const override; Chris@1406: void setVerticalZoomStep(int) override; Chris@1406: RangeMapper *getNewVerticalZoomRangeMapper() const override; Chris@133: Chris@1470: ModelId getSliceableModel() const override; Chris@193: Chris@0: protected slots: Chris@1481: void cacheInvalid(ModelId); Chris@1481: void cacheInvalid(ModelId, sv_frame_t startFrame, sv_frame_t endFrame); Chris@122: Chris@122: void preferenceChanged(PropertyContainer::PropertyName name); Chris@0: Chris@0: protected: Chris@1470: ModelId m_model; // a DenseTimeValueModel Chris@484: Chris@35: int m_channel; Chris@1023: int m_windowSize; Chris@35: WindowType m_windowType; Chris@1023: int m_windowHopLevel; Chris@1379: int m_oversampling; Chris@35: float m_gain; Chris@215: float m_initialGain; Chris@37: float m_threshold; Chris@215: float m_initialThreshold; Chris@35: int m_colourRotation; Chris@215: int m_initialRotation; Chris@1023: int m_minFrequency; Chris@1023: int m_maxFrequency; Chris@1023: int m_initialMaxFrequency; Chris@1106: ColourScaleType m_colourScale; Chris@1137: double m_colourScaleMultiple; Chris@197: int m_colourMap; Chris@1362: bool m_colourInverted; Chris@1239: mutable QColor m_crosshairColour; Chris@1104: BinScale m_binScale; Chris@1104: BinDisplay m_binDisplay; Chris@1104: ColumnNormalization m_normalization; // of individual columns Chris@1104: bool m_normalizeVisibleArea; Chris@133: int m_lastEmittedZoomStep; Chris@389: bool m_synchronous; Chris@0: Chris@608: mutable bool m_haveDetailedScale; Chris@215: Chris@1137: static std::pair convertToColourScale(int value); Chris@1137: static int convertFromColourScale(ColourScaleType type, double multiple); Chris@1104: static std::pair convertToColumnNorm(int value); Chris@1104: static int convertFromColumnNorm(ColumnNormalization norm, bool visible); Chris@1104: Chris@0: bool m_exiting; Chris@0: Chris@40: int getColourScaleWidth(QPainter &) const; Chris@40: Chris@918: void illuminateLocalFeatures(LayerGeometryProvider *v, QPainter &painter) const; Chris@121: Chris@905: double getEffectiveMinFrequency() const; Chris@905: double getEffectiveMaxFrequency() const; Chris@38: Chris@918: bool getXBinRange(LayerGeometryProvider *v, int x, double &windowMin, double &windowMax) const; Chris@918: bool getYBinRange(LayerGeometryProvider *v, int y, double &freqBinMin, double &freqBinMax) const; Chris@0: Chris@918: bool getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax) const; Chris@918: bool getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y, Chris@1266: double &freqMin, double &freqMax, Chris@1266: double &adjFreqMin, double &adjFreqMax) const; Chris@918: bool getXBinSourceRange(LayerGeometryProvider *v, int x, RealTime &timeMin, RealTime &timeMax) const; Chris@918: bool getXYBinSourceRange(LayerGeometryProvider *v, int x, int y, double &min, double &max, Chris@1266: double &phaseMin, double &phaseMax) const; Chris@0: Chris@805: int getWindowIncrement() const { Chris@97: if (m_windowHopLevel == 0) return m_windowSize; Chris@97: else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4; Chris@97: else return m_windowSize / (1 << (m_windowHopLevel - 1)); Chris@0: } Chris@113: Chris@1379: int getFFTSize() const; // m_windowSize * getOversampling() Chris@115: Chris@1473: // We take responsibility for registering/deregistering these Chris@1473: // models and caches with ModelById Chris@1472: ModelId m_fftModel; // an FFTModel Chris@1473: ModelId m_wholeCache; // a Dense3DModelPeakCache Chris@1473: ModelId m_peakCache; // a Dense3DModelPeakCache Chris@1450: int m_peakCacheDivisor; Chris@1450: void checkCacheSpace(int *suggestedPeakDivisor, Chris@1450: bool *createWholeCache) const; Chris@1211: void recreateFFTModel(); Chris@119: Chris@1030: typedef std::map ViewMagMap; // key is view id Chris@119: mutable ViewMagMap m_viewMags; Chris@1136: mutable ViewMagMap m_lastRenderedMags; // when in normalizeVisibleArea mode Chris@119: void invalidateMagnitudes(); Chris@1089: Chris@1089: typedef std::map ViewRendererMap; // key is view id Chris@1089: mutable ViewRendererMap m_renderers; Chris@1089: Colour3DPlotRenderer *getRenderer(LayerGeometryProvider *) const; Chris@1106: void invalidateRenderers(); Chris@1242: Chris@1242: void deleteDerivedModels(); Chris@1058: Chris@1106: void paintWithRenderer(LayerGeometryProvider *v, QPainter &paint, QRect rect) const; Chris@1142: Chris@1143: void paintDetailedScale(LayerGeometryProvider *v, Chris@1143: QPainter &paint, QRect rect) const; Chris@1143: void paintDetailedScalePhase(LayerGeometryProvider *v, Chris@1143: QPainter &paint, QRect rect) const; Chris@1058: Chris@1406: void updateMeasureRectYCoords(LayerGeometryProvider *v, Chris@1406: const MeasureRect &r) const override; Chris@1406: void setMeasureRectYCoord(LayerGeometryProvider *v, Chris@1406: MeasureRect &r, bool start, int y) const override; Chris@0: }; Chris@0: Chris@0: #endif