view data/model/FFTModel.h @ 1090:420fc961c0c4 simple-fft-model

Gut the old code, but don't replace it yet (so nothing will link yet)
author Chris Cannam
date Fri, 12 Jun 2015 14:51:46 +0100
parents 9f4505ac9072
children bdebff3265ae
line wrap: on
line source
/* -*- 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.
    
    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 FFT_MODEL_H
#define FFT_MODEL_H

#include "DenseThreeDimensionalModel.h"
#include "DenseTimeValueModel.h"

#include "base/Window.h"

#include <set>
#include <map>

/**
 * An implementation of DenseThreeDimensionalModel that makes FFT data
 * derived from a DenseTimeValueModel available as a generic data
 * grid.
 */
class FFTModel : public DenseThreeDimensionalModel
{
    Q_OBJECT

public:
    /**
     * Construct an FFT model derived from the given
     * DenseTimeValueModel, with the given window parameters and FFT
     * size (which may exceed the window size, for zero-padded FFTs).
     * 
     * If the model has multiple channels use only the given channel,
     * unless the channel is -1 in which case merge all available
     * channels.
     */
    FFTModel(const DenseTimeValueModel *model,
             int channel,
             WindowType windowType,
             int windowSize,
             int windowIncrement,
             int fftSize);
    ~FFTModel();

    // DenseThreeDimensionalModel and Model methods:
    //
    virtual int getWidth() const;
    virtual int getHeight() const;
    virtual float getValueAt(int x, int y) const { return getMagnitudeAt(x, y); }
    virtual bool isOK() const { return m_model && m_model->isOK(); }
    virtual sv_frame_t getStartFrame() const { return 0; }
    virtual sv_frame_t getEndFrame() const {
        return sv_frame_t(getWidth()) * getResolution() + getResolution();
    }
    virtual sv_samplerate_t getSampleRate() const {
        return isOK() ? m_model->getSampleRate() : 0;
    }
    virtual int getResolution() const { return m_windowIncrement; }
    virtual int getYBinCount() const { return getHeight(); }
    virtual float getMinimumLevel() const { return 0.f; } // Can't provide
    virtual float getMaximumLevel() const { return 1.f; } // Can't provide
    virtual Column getColumn(int x) const; // magnitudes
    virtual QString getBinName(int n) const;
    virtual bool shouldUseLogValueScale() const { return true; }
    virtual int getCompletion() const {
        int c = 100;
        if (m_model) (void)m_model->isReady(&c);
        return c;
    }
    virtual QString getError() const { return ""; } //!!!???
    virtual sv_frame_t getFillExtent() const { return getEndFrame(); }

    // FFTModel methods:
    //
    int getChannel() const { return m_channel; }
    WindowType getWindowType() const { return m_windowType; }
    int getWindowSize() const { return m_windowSize; }
    int getWindowIncrement() const { return m_windowIncrement; }
    int getFFTSize() const { return m_fftSize; }
    
    float getMagnitudeAt(int x, int y) const;
    float getNormalizedMagnitudeAt(int x, int y) const;
    float getMaximumMagnitudeAt(int x) const;
    float getPhaseAt(int x, int y) const;
    void getValuesAt(int x, int y, float &real, float &imaginary) const;
    bool isColumnAvailable(int x) const;
    bool getMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) const;
    bool getNormalizedMagnitudesAt(int x, float *values, int minbin = 0, int count = 0) const;
    bool getPhasesAt(int x, float *values, int minbin = 0, int count = 0) const;
    bool getValuesAt(int x, float *reals, float *imaginaries, int minbin = 0, int count = 0) const;

    /**
     * Calculate an estimated frequency for a stable signal in this
     * bin, using phase unwrapping.  This will be completely wrong if
     * the signal is not stable here.
     */
    virtual bool estimateStableFrequency(int x, int y, double &frequency);

    enum PeakPickType
    {
        AllPeaks,                /// Any bin exceeding its immediate neighbours
        MajorPeaks,              /// Peaks picked using sliding median window
        MajorPitchAdaptivePeaks  /// Bigger window for higher frequencies
    };

    typedef std::set<int> PeakLocationSet; // bin
    typedef std::map<int, double> PeakSet; // bin -> freq

    /**
     * Return locations of peak bins in the range [ymin,ymax].  If
     * ymax is zero, getHeight()-1 will be used.
     */
    virtual PeakLocationSet getPeaks(PeakPickType type, int x,
                                     int ymin = 0, int ymax = 0);

    /**
     * Return locations and estimated stable frequencies of peak bins.
     */
    virtual PeakSet getPeakFrequencies(PeakPickType type, int x,
                                       int ymin = 0, int ymax = 0);

    QString getTypeName() const { return tr("FFT"); }

public slots:
    void sourceModelAboutToBeDeleted();

private:
    FFTModel(const FFTModel &); // not implemented
    FFTModel &operator=(const FFTModel &); // not implemented

    const DenseTimeValueModel *m_model;
    int m_channel;
    WindowType m_windowType;
    int m_windowSize;
    int m_windowIncrement;
    int m_fftSize;
    Window<float> m_windower;
    
    int getPeakPickWindowSize(PeakPickType type, sv_samplerate_t sampleRate,
                              int bin, float &percentile) const;
};

#endif