svgui  1.9
SpectrogramLayer.h
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #ifndef _SPECTROGRAM_LAYER_H_
00017 #define _SPECTROGRAM_LAYER_H_
00018 
00019 #include "SliceableLayer.h"
00020 #include "base/Window.h"
00021 #include "base/RealTime.h"
00022 #include "base/Thread.h"
00023 #include "base/PropertyContainer.h"
00024 #include "data/model/PowerOfSqrtTwoZoomConstraint.h"
00025 #include "data/model/DenseTimeValueModel.h"
00026 #include "data/model/FFTModel.h"
00027 
00028 #include <QMutex>
00029 #include <QWaitCondition>
00030 #include <QImage>
00031 #include <QPixmap>
00032 
00033 class View;
00034 class QPainter;
00035 class QImage;
00036 class QPixmap;
00037 class QTimer;
00038 class FFTModel;
00039 class Dense3DModelPeakCache;
00040 
00041 
00047 class SpectrogramLayer : public SliceableLayer,
00048                          public PowerOfSqrtTwoZoomConstraint
00049 {
00050     Q_OBJECT
00051 
00052 public:
00053     enum Configuration { FullRangeDb, MelodicRange, MelodicPeaks };
00054     
00055     SpectrogramLayer(Configuration = FullRangeDb);
00056     ~SpectrogramLayer();
00057 
00058     virtual const ZoomConstraint *getZoomConstraint() const { return this; }
00059     virtual const Model *getModel() const { return m_model; }
00060     virtual void paint(View *v, QPainter &paint, QRect rect) const;
00061     virtual void setSynchronousPainting(bool synchronous);
00062 
00063     virtual int getVerticalScaleWidth(View *v, bool detailed, QPainter &) const;
00064     virtual void paintVerticalScale(View *v, bool detailed, QPainter &paint, QRect rect) const;
00065 
00066     virtual bool getCrosshairExtents(View *, QPainter &, QPoint cursorPos,
00067                                      std::vector<QRect> &extents) const;
00068     virtual void paintCrosshairs(View *, QPainter &, QPoint) const;
00069 
00070     virtual QString getFeatureDescription(View *v, QPoint &) const;
00071 
00072     virtual bool snapToFeatureFrame(View *v, int &frame,
00073                                     int &resolution,
00074                                     SnapType snap) const;
00075 
00076     virtual void measureDoubleClick(View *, QMouseEvent *);
00077 
00078     virtual bool hasLightBackground() const;
00079 
00080     void setModel(const DenseTimeValueModel *model);
00081 
00082     virtual PropertyList getProperties() const;
00083     virtual QString getPropertyLabel(const PropertyName &) const;
00084     virtual QString getPropertyIconName(const PropertyName &) const;
00085     virtual PropertyType getPropertyType(const PropertyName &) const;
00086     virtual QString getPropertyGroupName(const PropertyName &) const;
00087     virtual int getPropertyRangeAndValue(const PropertyName &,
00088                                          int *min, int *max, int *deflt) const;
00089     virtual QString getPropertyValueLabel(const PropertyName &,
00090                                           int value) const;
00091     virtual RangeMapper *getNewPropertyRangeMapper(const PropertyName &) const;
00092     virtual void setProperty(const PropertyName &, int value);
00093 
00099     void setChannel(int);
00100     int getChannel() const;
00101 
00102     void setWindowSize(int);
00103     int getWindowSize() const;
00104     
00105     void setWindowHopLevel(int level);
00106     int getWindowHopLevel() const;
00107 
00108     void setWindowType(WindowType type);
00109     WindowType getWindowType() const;
00110 
00111     void setZeroPadLevel(int level);
00112     int getZeroPadLevel() const;
00113 
00118     void setGain(float gain);
00119     float getGain() const;
00120 
00127     void setThreshold(float threshold);
00128     float getThreshold() const;
00129 
00130     void setMinFrequency(int);
00131     int getMinFrequency() const;
00132 
00133     void setMaxFrequency(int); // 0 -> no maximum
00134     int getMaxFrequency() const;
00135 
00136     enum ColourScale {
00137         LinearColourScale,
00138         MeterColourScale,
00139         dBSquaredColourScale,
00140         dBColourScale,
00141         PhaseColourScale
00142     };
00143 
00148     void setColourScale(ColourScale);
00149     ColourScale getColourScale() const;
00150 
00151     enum FrequencyScale {
00152         LinearFrequencyScale,
00153         LogFrequencyScale
00154     };
00155     
00159     void setFrequencyScale(FrequencyScale);
00160     FrequencyScale getFrequencyScale() const;
00161 
00162     enum BinDisplay {
00163         AllBins,
00164         PeakBins,
00165         PeakFrequencies
00166     };
00167     
00171     void setBinDisplay(BinDisplay);
00172     BinDisplay getBinDisplay() const;
00173  
00178     void setNormalizeColumns(bool n);
00179     bool getNormalizeColumns() const;
00180 
00184     void setNormalizeVisibleArea(bool n);
00185     bool getNormalizeVisibleArea() const;
00186 
00191     void setNormalizeHybrid(bool n);
00192     bool getNormalizeHybrid() const;
00193     
00194     void setColourMap(int map);
00195     int getColourMap() const;
00196 
00200     void setColourRotation(int);
00201     int getColourRotation() const;
00202 
00203     virtual VerticalPosition getPreferredFrameCountPosition() const {
00204         return PositionTop;
00205     }
00206 
00207     virtual bool isLayerOpaque() const { return true; }
00208 
00209     virtual ColourSignificance getLayerColourSignificance() const {
00210         return ColourHasMeaningfulValue;
00211     }
00212 
00213     float getYForFrequency(const View *v, float frequency) const;
00214     float getFrequencyForY(const View *v, int y) const;
00215 
00216     virtual int getCompletion(View *v) const;
00217     virtual QString getError(View *v) const;
00218 
00219     virtual bool getValueExtents(float &min, float &max,
00220                                  bool &logarithmic, QString &unit) const;
00221 
00222     virtual bool getDisplayExtents(float &min, float &max) const;
00223 
00224     virtual bool setDisplayExtents(float min, float max);
00225 
00226     virtual bool getYScaleValue(const View *, int, float &, QString &) const;
00227 
00228     virtual void toXml(QTextStream &stream, QString indent = "",
00229                        QString extraAttributes = "") const;
00230 
00231     void setProperties(const QXmlAttributes &attributes);
00232 
00233     virtual void setLayerDormant(const View *v, bool dormant);
00234 
00235     virtual bool isLayerScrollable(const View *) const { return false; }
00236 
00237     virtual int getVerticalZoomSteps(int &defaultStep) const;
00238     virtual int getCurrentVerticalZoomStep() const;
00239     virtual void setVerticalZoomStep(int);
00240     virtual RangeMapper *getNewVerticalZoomRangeMapper() const;
00241 
00242     virtual const Model *getSliceableModel() const;
00243 
00244 protected slots:
00245     void cacheInvalid();
00246     void cacheInvalid(int startFrame, int endFrame);
00247     
00248     void preferenceChanged(PropertyContainer::PropertyName name);
00249 
00250     void fillTimerTimedOut();
00251 
00252 protected:
00253     const DenseTimeValueModel *m_model; // I do not own this
00254 
00255     int                 m_channel;
00256     int              m_windowSize;
00257     WindowType          m_windowType;
00258     int              m_windowHopLevel;
00259     int              m_zeroPadLevel;
00260     int              m_fftSize;
00261     float               m_gain;
00262     float               m_initialGain;
00263     float               m_threshold;
00264     float               m_initialThreshold;
00265     int                 m_colourRotation;
00266     int                 m_initialRotation;
00267     int              m_minFrequency;
00268     int              m_maxFrequency;
00269     int              m_initialMaxFrequency;
00270     ColourScale         m_colourScale;
00271     int                 m_colourMap;
00272     QColor              m_crosshairColour;
00273     FrequencyScale      m_frequencyScale;
00274     BinDisplay          m_binDisplay;
00275     bool                m_normalizeColumns;
00276     bool                m_normalizeVisibleArea;
00277     bool                m_normalizeHybrid;
00278     int                 m_lastEmittedZoomStep;
00279     bool                m_synchronous;
00280 
00281     mutable bool        m_haveDetailedScale;
00282     mutable int         m_lastPaintBlockWidth;
00283     mutable RealTime    m_lastPaintTime;
00284 
00285     enum { NO_VALUE = 0 }; // colour index for unused pixels
00286 
00287     class Palette
00288     {
00289     public:
00290         QColor getColour(unsigned char index) const {
00291             return m_colours[index];
00292         }
00293     
00294         void setColour(unsigned char index, QColor colour) {
00295             m_colours[index] = colour;
00296         }
00297 
00298     private:
00299         QColor m_colours[256];
00300     };
00301 
00302     Palette m_palette;
00303 
00309     struct ImageCache
00310     {
00311         QImage image;
00312         QRect validArea;
00313         int startFrame;
00314         int zoomLevel;
00315     };
00316     typedef std::map<const View *, ImageCache> ViewImageCache;
00317     void invalidateImageCaches();
00318     void invalidateImageCaches(int startFrame, int endFrame);
00319     mutable ViewImageCache m_imageCaches;
00320 
00327     mutable QImage m_drawBuffer;
00328 
00329     mutable QTimer *m_updateTimer;
00330 
00331     mutable int m_candidateFillStartFrame;
00332     bool m_exiting;
00333 
00334     void initialisePalette();
00335     void rotatePalette(int distance);
00336 
00337     unsigned char getDisplayValue(View *v, float input) const;
00338 
00339     int getColourScaleWidth(QPainter &) const;
00340 
00341     void illuminateLocalFeatures(View *v, QPainter &painter) const;
00342 
00343     float getEffectiveMinFrequency() const;
00344     float getEffectiveMaxFrequency() const;
00345 
00346     struct LayerRange {
00347         int   startFrame;
00348         int    zoomLevel;
00349         int modelStart;
00350         int modelEnd;
00351     };
00352 
00353     // Note that the getYBin... methods return the nominal bin in the
00354     // un-smoothed spectrogram.  This is not necessarily the same bin
00355     // as is pulled from the spectrogram and drawn at the given
00356     // position, if the spectrogram has oversampling smoothing.  Use
00357     // getSmoothedYBinRange to obtain that.
00358 
00359     bool getXBinRange(View *v, int x, float &windowMin, float &windowMax) const;
00360     bool getYBinRange(View *v, int y, float &freqBinMin, float &freqBinMax) const;
00361     bool getSmoothedYBinRange(View *v, int y, float &freqBinMin, float &freqBinMax) const;
00362 
00363     bool getYBinSourceRange(View *v, int y, float &freqMin, float &freqMax) const;
00364     bool getAdjustedYBinSourceRange(View *v, int x, int y,
00365                                     float &freqMin, float &freqMax,
00366                                     float &adjFreqMin, float &adjFreqMax) const;
00367     bool getXBinSourceRange(View *v, int x, RealTime &timeMin, RealTime &timeMax) const;
00368     bool getXYBinSourceRange(View *v, int x, int y, float &min, float &max,
00369                              float &phaseMin, float &phaseMax) const;
00370 
00371     int getWindowIncrement() const {
00372         if (m_windowHopLevel == 0) return m_windowSize;
00373         else if (m_windowHopLevel == 1) return (m_windowSize * 3) / 4;
00374         else return m_windowSize / (1 << (m_windowHopLevel - 1));
00375     }
00376 
00377     int getZeroPadLevel(const View *v) const;
00378     int getFFTSize(const View *v) const;
00379     FFTModel *getFFTModel(const View *v) const;
00380     Dense3DModelPeakCache *getPeakCache(const View *v) const;
00381     void invalidateFFTModels();
00382 
00383     typedef std::pair<FFTModel *, int> FFTFillPair; // model, last fill
00384     typedef std::map<const View *, FFTFillPair> ViewFFTMap;
00385     typedef std::map<const View *, Dense3DModelPeakCache *> PeakCacheMap;
00386     mutable ViewFFTMap m_fftModels;
00387     mutable PeakCacheMap m_peakCaches;
00388     mutable Model *m_sliceableModel;
00389 
00390     class MagnitudeRange {
00391     public:
00392         MagnitudeRange() : m_min(0), m_max(0) { }
00393         bool operator==(const MagnitudeRange &r) {
00394             return r.m_min == m_min && r.m_max == m_max;
00395         }
00396         bool isSet() const { return (m_min != 0 || m_max != 0); }
00397         void set(float min, float max) {
00398             m_min = convert(min);
00399             m_max = convert(max);
00400             if (m_max < m_min) m_max = m_min;
00401         }
00402         bool sample(float f) {
00403             unsigned int ui = convert(f);
00404             bool changed = false;
00405             if (isSet()) {
00406                 if (ui < m_min) { m_min = ui; changed = true; }
00407                 if (ui > m_max) { m_max = ui; changed = true; }
00408             } else {
00409                 m_max = m_min = ui;
00410                 changed = true;
00411             }
00412             return changed;
00413         }            
00414         bool sample(const MagnitudeRange &r) {
00415             bool changed = false;
00416             if (isSet()) {
00417                 if (r.m_min < m_min) { m_min = r.m_min; changed = true; }
00418                 if (r.m_max > m_max) { m_max = r.m_max; changed = true; }
00419             } else {
00420                 m_min = r.m_min;
00421                 m_max = r.m_max;
00422                 changed = true;
00423             }
00424             return changed;
00425         }            
00426         float getMin() const { return float(m_min) / UINT_MAX; }
00427         float getMax() const { return float(m_max) / UINT_MAX; }
00428     private:
00429         unsigned int m_min;
00430         unsigned int m_max;
00431         unsigned int convert(float f) {
00432             if (f < 0.f) f = 0.f;
00433             if (f > 1.f) f = 1.f;
00434             return (unsigned int)(f * UINT_MAX);
00435         }
00436     };
00437 
00438     typedef std::map<const View *, MagnitudeRange> ViewMagMap;
00439     mutable ViewMagMap m_viewMags;
00440     mutable std::vector<MagnitudeRange> m_columnMags;
00441     void invalidateMagnitudes();
00442     bool updateViewMagnitudes(View *v) const;
00443     bool paintDrawBuffer(View *v, int w, int h,
00444                          int *binforx, float *binfory,
00445                          bool usePeaksCache,
00446                          MagnitudeRange &overallMag,
00447                          bool &overallMagChanged) const;
00448     bool paintDrawBufferPeakFrequencies(View *v, int w, int h,
00449                                         int *binforx,
00450                                         int minbin,
00451                                         int maxbin,
00452                                         float displayMinFreq,
00453                                         float displayMaxFreq,
00454                                         bool logarithmic,
00455                                         MagnitudeRange &overallMag,
00456                                         bool &overallMagChanged) const;
00457 
00458     virtual void updateMeasureRectYCoords(View *v, const MeasureRect &r) const;
00459     virtual void setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const;
00460 };
00461 
00462 #endif