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 <QMutex>
Chris@0: #include <QWaitCondition>
Chris@95: #include <QImage>
Chris@95: #include <QPixmap>
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@0:     virtual const ZoomConstraint *getZoomConstraint() const { return this; }
Chris@0:     virtual const Model *getModel() const { return m_model; }
Chris@916:     virtual void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const;
Chris@389:     virtual void setSynchronousPainting(bool synchronous);
Chris@0: 
Chris@918:     virtual int getVerticalScaleWidth(LayerGeometryProvider *v, bool detailed, QPainter &) const;
Chris@918:     virtual void paintVerticalScale(LayerGeometryProvider *v, bool detailed, QPainter &paint, QRect rect) const;
Chris@0: 
Chris@918:     virtual bool getCrosshairExtents(LayerGeometryProvider *, QPainter &, QPoint cursorPos,
Chris@77:                                      std::vector<QRect> &extents) const;
Chris@918:     virtual void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const;
Chris@77: 
Chris@918:     virtual QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const;
Chris@0: 
Chris@918:     virtual bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
Chris@1266:                                     int &resolution,
Chris@1266:                                     SnapType snap) const;
Chris@13: 
Chris@918:     virtual void measureDoubleClick(LayerGeometryProvider *, QMouseEvent *);
Chris@283: 
Chris@224:     virtual bool hasLightBackground() const;
Chris@224: 
Chris@0:     void setModel(const DenseTimeValueModel *model);
Chris@0: 
Chris@0:     virtual PropertyList getProperties() const;
Chris@87:     virtual QString getPropertyLabel(const PropertyName &) const;
Chris@335:     virtual QString getPropertyIconName(const PropertyName &) const;
Chris@0:     virtual PropertyType getPropertyType(const PropertyName &) const;
Chris@0:     virtual QString getPropertyGroupName(const PropertyName &) const;
Chris@0:     virtual int getPropertyRangeAndValue(const PropertyName &,
Chris@216:                                          int *min, int *max, int *deflt) const;
Chris@0:     virtual QString getPropertyValueLabel(const PropertyName &,
Chris@1266:                                           int value) const;
Chris@862:     virtual QString getPropertyValueIconName(const PropertyName &,
Chris@862:                                              int value) const;
Chris@167:     virtual RangeMapper *getNewPropertyRangeMapper(const PropertyName &) const;
Chris@0:     virtual void setProperty(const PropertyName &, int value);
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@0:     virtual VerticalPosition getPreferredFrameCountPosition() const {
Chris@1266:         return PositionTop;
Chris@0:     }
Chris@0: 
Chris@15:     virtual bool isLayerOpaque() const { return true; }
Chris@287: 
Chris@287:     virtual ColourSignificance getLayerColourSignificance() const {
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@1113:     double getYForBin(const LayerGeometryProvider *, double bin) const;
Chris@1113:     double getBinForY(const LayerGeometryProvider *, double y) const;
Chris@1085:     
Chris@918:     virtual int getCompletion(LayerGeometryProvider *v) const;
Chris@918:     virtual QString getError(LayerGeometryProvider *v) const;
Chris@0: 
Chris@905:     virtual bool getValueExtents(double &min, double &max,
Chris@101:                                  bool &logarithmic, QString &unit) const;
Chris@101: 
Chris@905:     virtual bool getDisplayExtents(double &min, double &max) const;
Chris@79: 
Chris@905:     virtual bool setDisplayExtents(double min, double max);
Chris@120: 
Chris@918:     virtual bool getYScaleValue(const LayerGeometryProvider *, int, double &, QString &) const;
Chris@261: 
Chris@316:     virtual void toXml(QTextStream &stream, QString indent = "",
Chris@316:                        QString extraAttributes = "") const;
Chris@6: 
Chris@11:     void setProperties(const QXmlAttributes &attributes);
Chris@11: 
Chris@918:     virtual void setLayerDormant(const LayerGeometryProvider *v, bool dormant);
Chris@29: 
Chris@1232:     virtual bool isLayerScrollable(const LayerGeometryProvider *) const;
Chris@94: 
Chris@133:     virtual int getVerticalZoomSteps(int &defaultStep) const;
Chris@133:     virtual int getCurrentVerticalZoomStep() const;
Chris@133:     virtual void setVerticalZoomStep(int);
Chris@187:     virtual RangeMapper *getNewVerticalZoomRangeMapper() const;
Chris@133: 
Chris@193:     virtual const Model *getSliceableModel() const;
Chris@193: 
Chris@0: protected slots:
Chris@0:     void cacheInvalid();
Chris@906:     void cacheInvalid(sv_frame_t startFrame, sv_frame_t endFrame);
Chris@122:     
Chris@122:     void preferenceChanged(PropertyContainer::PropertyName name);
Chris@0: 
Chris@0: protected:
Chris@0:     const DenseTimeValueModel *m_model; // I do not own this
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<ColourScaleType, double> convertToColourScale(int value);
Chris@1137:     static int convertFromColourScale(ColourScaleType type, double multiple);
Chris@1104:     static std::pair<ColumnNormalization, bool> 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@1211:     FFTModel *m_fftModel;
Chris@1211:     FFTModel *getFFTModel() const { return m_fftModel; }
Chris@1212:     Dense3DModelPeakCache *m_wholeCache;
Chris@1211:     Dense3DModelPeakCache *m_peakCache;
Chris@1211:     Dense3DModelPeakCache *getPeakCache() const { return m_peakCache; }
Chris@1054:     const int m_peakCacheDivisor;
Chris@1212:     bool canStoreWholeCache() const;
Chris@1211:     void recreateFFTModel();
Chris@119: 
Chris@1030:     typedef std::map<int, MagnitudeRange> 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<int, Colour3DPlotRenderer *> 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@1058:     virtual void updateMeasureRectYCoords(LayerGeometryProvider *v,
Chris@1058:                                           const MeasureRect &r) const;
Chris@1058:     virtual void setMeasureRectYCoord(LayerGeometryProvider *v,
Chris@1058:                                       MeasureRect &r, bool start, int y) const;
Chris@0: };
Chris@0: 
Chris@0: #endif