File: SpectrogramLayer.h

package info (click to toggle)
sonic-visualiser 5.2.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 24,744 kB
  • sloc: cpp: 158,888; ansic: 11,920; sh: 1,785; makefile: 517; xml: 64; perl: 31
file content (391 lines) | stat: -rw-r--r-- 14,242 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

/*
    Sonic Visualiser
    An audio file viewer and annotation editor.
    Centre for Digital Music, Queen Mary, University of London.
    This file copyright 2006 Chris Cannam and QMUL.
    
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.
*/

#ifndef SPECTROGRAM_LAYER_H
#define SPECTROGRAM_LAYER_H

#include "SliceableLayer.h"
#include "base/Window.h"
#include "base/MagnitudeRange.h"
#include "base/RealTime.h"
#include "base/Thread.h"
#include "base/PropertyContainer.h"
#include "data/model/PowerOfSqrtTwoZoomConstraint.h"
#include "data/model/DenseTimeValueModel.h"
#include "data/model/FFTModel.h"

#include "VerticalBinLayer.h"
#include "ColourScale.h"
#include "Colour3DPlotRenderer.h"

#include <QMutex>
#include <QWaitCondition>

class QPainter;
class QTimer;

namespace sv {

class View;
class FFTModel;
class Dense3DModelPeakCache;

/**
 * SpectrogramLayer represents waveform data (obtained from a
 * DenseTimeValueModel) in spectrogram form.
 */

class SpectrogramLayer : public VerticalBinLayer,
                         public PowerOfSqrtTwoZoomConstraint
{
    Q_OBJECT

public:
    enum Configuration { FullRangeDb, MelodicRange, MelodicPeaks };

    /**
     * Construct a SpectrogramLayer with default parameters
     * appropriate for the given configuration.
     */
    SpectrogramLayer(Configuration = FullRangeDb);
    ~SpectrogramLayer();
    
    const ZoomConstraint *getZoomConstraint() const override { return this; }
    ModelId getModel() const override { return m_model; }

    ModelId getExportModel(LayerGeometryProvider *) const override;

    void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const override;
    void setSynchronousPainting(bool synchronous) override;

    int getVerticalScaleWidth(LayerGeometryProvider *v, bool detailed, QPainter &) const override;
    void paintVerticalScale(LayerGeometryProvider *v, bool detailed, QPainter &paint, QRect rect) const override;

    bool getCrosshairExtents(LayerGeometryProvider *, QPainter &, QPoint cursorPos,
                             std::vector<QRect> &extents) const override;
    void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const override;

    QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const override;

    bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
                            int &resolution,
                            SnapType snap, int ycoord) const override;

    void measureDoubleClick(LayerGeometryProvider *, QMouseEvent *) override;

    bool hasLightBackground() const override;

    void setModel(ModelId model); // a DenseTimeValueModel

    PropertyList getProperties() const override;
    QString getPropertyLabel(const PropertyName &) const override;
    QString getPropertyIconName(const PropertyName &) const override;
    PropertyType getPropertyType(const PropertyName &) const override;
    QString getPropertyGroupName(const PropertyName &) const override;
    int getPropertyRangeAndValue(const PropertyName &,
                                 int *min, int *max, int *deflt) const override;
    QString getPropertyValueLabel(const PropertyName &,
                                          int value) const override;
    QString getPropertyValueIconName(const PropertyName &,
                                             int value) const override;
    RangeMapper *getNewPropertyRangeMapper(const PropertyName &) const override;
    void setProperty(const PropertyName &, int value) override;

    /**
     * Specify the channel to use from the source model.
     * A value of -1 means to mix all available channels.
     * The default is channel 0.
     */
    void setChannel(int);
    int getChannel() const;

    void setWindowSize(int);
    int getWindowSize() const;
    
    void setWindowHopLevel(int level);
    int getWindowHopLevel() const;

    void setOversampling(int oversampling);
    int getOversampling() const;
    
    void setWindowType(WindowType type);
    WindowType getWindowType() const;

    /**
     * Set the gain multiplier for sample values in this view.
     * The default is 1.0.
     */
    void setGain(float gain);
    float getGain() const;

    /**
     * Set the threshold for sample values to qualify for being shown
     * in the FFT, in voltage units.
     *
     * The default is 10^-8 (-80dB).
     */
    void setThreshold(float threshold);
    float getThreshold() const;

    /**
     * Mark the spectrogram layer as having a fixed range in the
     * vertical axis. This indicates that the visible frequency range
     * is determined entirely by the configuration requested on
     * construction, and that setMinFrequency, setMaxFrequency, and
     * setDisplayExtents will never be called. This may allow some
     * cache-size-related optimisations. It should be called
     * immediately after construction, if at all.
     *
     * Note that this cannot be reversed on a given object (this call
     * takes no argument and there is no inverse call).
     */
    void setVerticallyFixed();

    void setMinFrequency(int);
    int getMinFrequency() const;

    void setMaxFrequency(int); // 0 -> no maximum
    int getMaxFrequency() const;

    /**
     * Specify the scale for sample levels.  See ColourScale and
     * WaveformLayer for comparison and details of meter and dB
     * scaling.  The default is LogColourScale.
     */
    void setColourScale(ColourScaleType);
    ColourScaleType getColourScale() const;

    /**
     * Specify multiple factor for colour scale. This is 2.0 for
     * log-power spectrogram and 1.0 otherwise.
     */
    void setColourScaleMultiple(double);
    double getColourScaleMultiple() const;
    
    /**
     * Specify the scale for the y axis. This function can be used to
     * choose log or linear only and is here for backward
     * compatibility. Use setFrequencyMapping in new code.
     */
    void setBinScale(BinScale);

    /**
     * Specify the scale mapping for the y axis.
     */
    void setFrequencyMapping(FrequencyMapping);
    FrequencyMapping getFrequencyMapping() const;

    /**
     * Specify the processing of frequency bins for the y axis.
     */
    void setBinDisplay(BinDisplay);
    BinDisplay getBinDisplay() const;

    /**
     * Specify the normalization mode for individual columns.
     */
    void setNormalization(ColumnNormalization);
    ColumnNormalization getNormalization() const;

    /**
     * Specify whether to normalize the visible area.
     */
    void setNormalizeVisibleArea(bool);
    bool getNormalizeVisibleArea() const;

    /**
     * Specify the colour map. See ColourMapper for the colour map
     * values.
     */
    void setColourMap(int map);
    int getColourMap() const;

    /**
     * Specify the colourmap rotation for the colour scale.
     */
    void setColourRotation(int);
    int getColourRotation() const;

    void setOpaque(bool i);
    bool getOpaque() const;

    void setSmooth(bool i);
    bool getSmooth() const;

    VerticalPosition getPreferredFrameCountPosition() const override {
        return PositionTop;
    }

    bool isLayerOpaque() const override { return m_opaque; }

    ColourSignificance getLayerColourSignificance() const override {
        return ColourHasMeaningfulValue;
    }

    double getYForFrequency(const LayerGeometryProvider *v, double frequency) const;
    double getFrequencyForY(const LayerGeometryProvider *v, int y) const;

    //!!! VerticalBinLayer methods. Note overlap with get*BinRange()
    double getYForBin(const LayerGeometryProvider *, double bin) const override;
    double getBinForY(const LayerGeometryProvider *, double y) const override;
    
    int getCompletion(LayerGeometryProvider *v) const override;
    QString getError(LayerGeometryProvider *v) const override;

    ScaleExtents getVerticalExtents() const override;
    
    bool getDisplayExtents(double &min, double &max) const override;

    bool setDisplayExtents(double min, double max) override;

    bool getYScaleValue(const LayerGeometryProvider *, int, double &, QString &) const override;

    void toXml(QTextStream &stream, QString indent = "",
                       QString extraAttributes = "") const override;

    void setProperties(const LayerAttributes &attributes) override;

    void setLayerDormant(const LayerGeometryProvider *v, bool dormant) override;

    bool isLayerScrollable(const LayerGeometryProvider *) const override;

    int getVerticalZoomSteps(int &defaultStep) const override;
    int getCurrentVerticalZoomStep() const override;
    void setVerticalZoomStep(int) override;
    RangeMapper *getNewVerticalZoomRangeMapper() const override;

    ModelId getSliceableModel() const override;

protected slots:
    // Because the modelChanged signals are called directly from the
    // model, and not from something in the UI, they take the
    // discretionary property mutex before calling cacheInvalid
    void modelChanged(ModelId);
    void modelChangedWithin(ModelId, sv_frame_t, sv_frame_t);

    // These are the same as the above but without the mutex
    void cacheInvalid(ModelId);
    void cacheInvalid(ModelId, sv_frame_t startFrame, sv_frame_t endFrame);
    
    void preferenceChanged(PropertyContainer::PropertyName name);

protected:
    ModelId m_model; // a DenseTimeValueModel

    int                 m_channel;
    int                 m_windowSize;
    WindowType          m_windowType;
    int                 m_windowHopLevel;
    int                 m_oversampling;
    float               m_gain;
    float               m_initialGain;
    float               m_threshold;
    float               m_initialThreshold;
    int                 m_colourRotation;
    int                 m_initialRotation;
    int                 m_minFrequency;
    int                 m_maxFrequency;
    int                 m_initialMaxFrequency;
    bool                m_verticallyFixed;
    ColourScaleType     m_colourScale;
    double              m_colourScaleMultiple;
    int                 m_colourMap;
    bool                m_colourInverted;
    mutable QColor      m_crosshairColour;
    FrequencyMapping    m_frequencyMapping;
    BinDisplay          m_binDisplay;
    ColumnNormalization m_normalization; // of individual columns
    bool                m_normalizeVisibleArea;
    bool                m_opaque;
    bool                m_smooth;
    int                 m_lastEmittedZoomStep;
    bool                m_synchronous;

    mutable bool        m_haveDetailedScale;

    static std::pair<ColourScaleType, double> convertToColourScale(int value);
    static int convertFromColourScale(ColourScaleType type, double multiple);
    static std::pair<ColumnNormalization, bool> convertToColumnNorm(int value);
    static int convertFromColumnNorm(ColumnNormalization norm, bool visible);

    bool m_exiting;

    int getColourScaleWidth(QPainter &) const;

    void illuminateLocalFeatures(LayerGeometryProvider *v, QPainter &painter) const;

    double getEffectiveMinFrequency() const;
    double getEffectiveMaxFrequency() const;

    bool getXBinRange(LayerGeometryProvider *v, int x, double &windowMin, double &windowMax) const;
    bool getYBinRange(LayerGeometryProvider *v, int y, double &freqBinMin, double &freqBinMax) const;

    bool getYBinSourceRange(LayerGeometryProvider *v, int y, double &freqMin, double &freqMax) const;
    bool getAdjustedYBinSourceRange(LayerGeometryProvider *v, int x, int y,
                                    double &freqMin, double &freqMax,
                                    double &adjFreqMin, double &adjFreqMax) const;
    bool getXBinSourceRange(LayerGeometryProvider *v, int x, RealTime &timeMin, RealTime &timeMax) const;
    bool getXYBinSourceRange(LayerGeometryProvider *v, int x, int y, double &min, double &max,
                             double &phaseMin, double &phaseMax) const;

    int 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));
    }

    int getFFTSize() const; // m_windowSize * getOversampling()

    // We take responsibility for registering/deregistering these
    // models and caches with ModelById
    ModelId m_fftModel; // an FFTModel
    ModelId m_wholeCache; // a Dense3DModelPeakCache
    ModelId m_peakCache; // a Dense3DModelPeakCache
    int m_peakCacheDivisor;
    
    mutable std::vector<ModelId> m_exporters; // used, waiting to be released
    
    void checkCacheSpace(int *suggestedPeakDivisor,
                         bool *createWholeCache) const;
    void recreateFFTModel();

    typedef std::map<int, MagnitudeRange> ViewMagMap; // key is view id
    mutable ViewMagMap m_viewMags;
    mutable ViewMagMap m_lastRenderedMags; // when in normalizeVisibleArea mode
    void invalidateMagnitudes();

    typedef std::map<int, Colour3DPlotRenderer *> ViewRendererMap; // key is view id
    mutable ViewRendererMap m_renderers;
    Colour3DPlotRenderer *getRenderer(LayerGeometryProvider *) const;
    void invalidateRenderers();

    void deleteDerivedModels();
    
    void paintWithRenderer(LayerGeometryProvider *v, QPainter &paint, QRect rect) const;

    void paintDetailedScale(LayerGeometryProvider *v,
                            QPainter &paint, QRect rect) const;
    void paintDetailedScalePhase(LayerGeometryProvider *v,
                                 QPainter &paint, QRect rect) const;
    
    void updateMeasureRectYCoords(LayerGeometryProvider *v,
                                          const MeasureRect &r) const override;
    void setMeasureRectYCoord(LayerGeometryProvider *v,
                                      MeasureRect &r, bool start, int y) const override;
};

} // end namespace sv

#endif