view FreqView.h @ 0:3004dd663202

first import
author Fiore Martin <f.martin@qmul.ac.uk>
date Fri, 26 Feb 2016 14:49:35 +0000
parents
children
line wrap: on
line source
#pragma once
#include "IControl.h"

#include <vector>

class FreqView : public IControl
{

    int mNumBins;
    std::vector<float> mBins;
    std::vector<float> mPeaks;
    double mSampleRate;
    double mHalfSampleRate;
    double mDecayAmount;
    double mSelectionStart;
    double mSelectionSize;
    double mThreshold;
    
    IRECT mPad;

public:
    
    static const double kPeakDecayRate;
    static const double kMaxPeakDB;
    static const double kZeroDbY;
    static const IColor kGridColor;
    static const IColor kBgColor;
    static const IColor kPadColor;
    static const IChannelBlend kSelectionBlend;
    
    FreqView(IPlugBase *pPlug, IRECT pR, int numBins) :
        IControl(pPlug, pR),
        mGrid(*this),
        mNumBins(numBins),
        mBins(numBins, 0.0f),
        mPeaks(numBins, 0.0f),
        mSelectionStart(0),
        mSelectionSize(1),
        mSampleRate(44100),
        mHalfSampleRate(44100/2),
        mPad(pR.GetPadded(4))
        
    { }

    ~FreqView(){}

    bool Draw(IGraphics* pGraphics) override
    {
        
        pGraphics->FillIRect(&kPadColor, &mPad);
        pGraphics->FillIRect(&kBgColor, &mRECT);
        
        /* draw grid */
        mGrid.Draw(pGraphics);
        
        /* draw the frequency scope */
        for (int i = 1; i < mNumBins; i++){
            //DrawBin(pGraphics, i);
            
            int x1 = mRECT.L + (float(i-1) / mNumBins * mRECT.W());
            int x2 = mRECT.L + (float(i) / mNumBins * mRECT.W());
            
            /* max between new peak and old peak decay wins */
            mPeaks[i] = IPMAX(AmpToMeter(mBins[i], kMaxPeakDB) , mPeaks[i] - mDecayAmount);
            
            int y1 = mRECT.T + (mRECT.H() *  (1 - mPeaks[i-1]));
            int y2 = mRECT.T + (mRECT.H() *  (1 - mPeaks[i]));
            
            
            pGraphics->DrawLine(&COLOR_WHITE, x1, y1, x2, y2 );
        }
        
        /* draw the selection */
        //pGraphics->DrawVerticalLine(&COLOR_GREEN, mRECT.L + (mRECT.W() * (mSelectionStart/mHalfSampleRate)) , mRECT.B, mRECT.T);
        int left = mRECT.L + (mRECT.W() * (mSelectionStart/mHalfSampleRate));
        int right = left + (mRECT.W() * (mSelectionSize/mHalfSampleRate));
        int top = mRECT.T + (mRECT.H() *  (1 - DbToMeter(mThreshold, kMaxPeakDB)));
        
        IRECT selRect(left , top, right, mRECT.B);
        IRECT peakRect(left, mRECT.T, right, top);
        
        pGraphics->FillIRect(&COLOR_GREEN, &selRect, &kSelectionBlend);
        pGraphics->FillIRect(&COLOR_RED, &peakRect, &kSelectionBlend);
        
        return true;
    }



    bool IsDirty() override
    {
        return true;
    }

    static double AmpToMeter(double amplitudeVal, double maxDB)
    {
        double db;
        if (amplitudeVal > 0)
            db = ::AmpToDB(amplitudeVal);
        else
            db = -999;
        return BOUNDED((db + 60) / maxDB, 0, 1);
    }
    
    static double DbToMeter(double dbVal, double maxDB)
    {
        return BOUNDED((dbVal + 60) / maxDB, 0, 1);
    }

    void setBins(float * compBins)
    {
        for (int i = 0; i < mNumBins; i++){
            mBins[i] = compBins[i];
        }
        SetDirty(false);
        Redraw();
    }
    
    inline void setSelectionStart(double startHz)
    {
        mSelectionStart = startHz;
    }
    
    inline double getSelectionStart() const
    {
        return mSelectionStart;
    }
    
    inline void setSelectionSize(double sizeHz)
    {
        mSelectionSize = sizeHz;
    }
    
    inline double getSelectionSize() const
    {
        return mSelectionSize;
    }
    
    inline void setThreshold(double thresDb)
    {
        mThreshold = thresDb;
    }
    
    inline void setSampleRate(double sampleRate)
    {
        mSampleRate = sampleRate;
        mHalfSampleRate = sampleRate/2;
        const double deltaT = mNumBins / sampleRate;
        mDecayAmount = deltaT * kPeakDecayRate;
        
        /* reset selection with the new sampling rate */
        setSelectionStart(mSelectionStart);
        setSelectionSize(mSelectionSize);
    }
    
    
    class Grid
    {
        /* const reference to enclosing class */
        const FreqView & mView;
        std::vector<double> mHlines;
    public:
        
        static const IColor kZeroDbLineColor;
        
        Grid(const FreqView &v ): mView(v)
        {
            for (int db=-60; db<kMaxPeakDB; db += 6){
                if(db == 0){
                    continue; // 0 db has already the colored line
                }
                
                const IRECT & r = mView.mRECT;
                double lineRatio = DbToMeter(db, FreqView::kMaxPeakDB);
                mHlines.push_back(r.B - r.H() * lineRatio);
            }
        }

        
        void Draw(IGraphics* pGraphics)
        {
            const IRECT & r = mView.mRECT;
            
            /* draw horizontal lines */
            for(double & l : mHlines){
                pGraphics->DrawHorizontalLine(&FreqView::kGridColor, l, r.L, r.R);
            }
            
            /* draw vertical lines */
            for(int i=1000; i<mView.mHalfSampleRate; i += 1000){
                double ratio = i/mView.mHalfSampleRate;
                double x = r.L + r.W()*ratio;
                
                pGraphics->DrawVerticalLine(&kGridColor, x , r.T, r.B);
            }
            
            /* draw the 0 dB horiz line */
            pGraphics->DrawHorizontalLine(&kZeroDbLineColor, r.B - (r.H() * FreqView::kZeroDbY), r.L, r.R );

        }
        
    } mGrid;
};