/***************************************************************************
 *   Copyright (C) 2004 by Predrag Viceic                                  *
 *   viceic@net2000.ch                                             *
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "wavecanvas.h"
#include "rms.h"
/**
        \fn WaveCanvas::WaveCanvas(QWidget* parent)
        Initialises member variables
    */
WaveCanvas::WaveCanvas(QWidget* parent)
 : QCanvas(parent)
{
    zoomRatio=1;
    soundManager=0;
    bgColor=Qt::white;
    spectrumBgColor=Qt::blue;
    _hasRuler=FALSE;
    maxZoomRatio=-1;
    background=0;
    backgroundPix=0;
    viewMode=WAVE_VIEWMODE;
    drawing=FALSE;
    pixmapXOrigin=0;
    hasPixmapV=FALSE;
    leftMaximaBuffer=0;
    rightMaximaBuffer=0;
    leftRMSBuffer=0;
    rightRMSBuffer=0;
    spectrogramMaxBuffer=0;
    spectrogramMaxBufferNbValues=0;
    maxBufferNbValues=0;
    visibleWidth=0;
    rmsL=rms_env_new();
    rmsR=rms_env_new();
}


WaveCanvas::~WaveCanvas()
{
    //zapBuffers();
    QCanvasItemList all=allItems();
    QCanvasItemList::iterator it;
    for ( it = all.begin(); it != all.end(); ++it ){
        (*it)->hide();
    }
    rms_env_free(rmsL);
    rms_env_free(rmsR);
}

/**
        \fn WaveCanvas::drawBackgroundImage(long start_sample, long end_sample)

        launches drawSpectrum(..) or drawWave(..) depending on view mode

        \sa drawWave(long,long)
        \sa drawSpectrum(long,long)
        \sa drawBackground()
*/
void WaveCanvas::drawBackgroundImage(long start_sample, long end_sample){
    //cout<<"in wavecanvas (parent ["<<parent()->parent()->name()<<"]) drawBackgroundImage()\n";
    if(viewMode==SPECTRUM_VIEWMODE) drawSpectrum(start_sample,end_sample);
    else drawWave(start_sample,end_sample);
}

/**
        \fn WaveCanvas::drawBackground( QPainter & localpainter, const QRect & clip )

        Reimplements the QCanvas::drawBackground. Copies computed pixmap onto background pixmap

        \sa drawWave(long,long)
        \sa drawSpectrum(long,long)
        \sa drawBackgroundImage(long,long)
*/
void WaveCanvas::drawBackground( QPainter & localpainter, const QRect & clip ){
        if(soundManager!=0 && soundManager->hasSound()){
            if(backgroundPix){
                localpainter.drawPixmap(clip.x(),0,
                                                    *backgroundPix,
                                                    clip.x()-pixmapXOrigin,0,
                                                    clip.width(),backgroundPix->height());
            }
        }
}




/*!
    \fn WaveCanvas::setZoomRatio(long)

    sets the zoom ratio and computes the max zoom ratio (used for ruler coord system)

 */
void WaveCanvas::setZoomRatio(long zr)
{
    if(visibleWidth>0){
        zoomRatio=zr;
        maxZoomRatio=soundManager->getFrames()/visibleWidth;
    }
}


/*!
    \fn WaveCanvas::setSoundManager(SoudManager*)

    assigns the pointer to the current SoundManager
 */
void WaveCanvas::setSoundManager(SoundManager* sm)
{
	soundManager=sm;
}




/*!
    \fn WaveCanvas::setBgColor(int r, int g, int b)

 */
void WaveCanvas::setBgColor(int r, int g, int b)
{
    bgColor.setRgb(r,g,b);
}


/*!
    \fn WaveCanvas::hasRuler(bool)
 */
void WaveCanvas::hasRuler(bool _hr)
{
    _hasRuler=_hr;
}


/*!
    \fn WaveCanvas::getRulerWidth();
 */
int WaveCanvas::getRulerHeight()
{
    if(_hasRuler) return 20;
    else return 0;
}


/*!
    \fn WaveCanvas::forceRepaint()

    forces the repaint of the visible part of canvas

    \sa forceRepaint(long, long)
 */
void WaveCanvas::forceRepaint()
{
    if(backgroundPix && backgroundPix->width()>0){
        long start_sample=pixmapXOrigin*zoomRatio;
        long end_sample= start_sample+visibleWidth*zoomRatio;
        
        cout<<"S: "<<start_sample<<" E: "<<end_sample<<" PX: "<<pixmapXOrigin<<" Z: "<<zoomRatio<<"\n";
        /*
        assert(start_sample>=0 &&
                end_sample<=soundManager->getFrames() && end_sample>start_sample);
        */
        end_sample=end_sample>=soundManager->getFrames()?soundManager->getFrames():end_sample;
        forceRepaint(start_sample,end_sample);
    }else{
        forceRepaint(0,soundManager->getFrames());
    }

}
/*!
    \fn WaveCanvas::forceRepaint(long start_sample, long end_sample)

    forces the repaint of the canvas from start_sample to end_sample

    \sa forceRepaint()
 */
void WaveCanvas::forceRepaint(long start_sample,long end_sample)
{
    /**
       \todo find out why sometimes extremly huge or negative values enter here
    */

    //cout<<"repainting from "<<start_sample<<" to "<<end_sample<<" pixmap origin "<<pixmapXOrigin<<"\n";
    assert(start_sample>=0);
    //assert(end_sample<=soundManager->getFrames());
    end_sample=end_sample<=soundManager->getFrames()?end_sample:soundManager->getFrames();
    cout<<"start: "<<start_sample<<" end: "<<end_sample<<"\n";
    assert(end_sample>start_sample);
    if(start_sample>=0 && end_sample>0 && end_sample<=soundManager->getFrames()){
        drawBackgroundImage(start_sample,end_sample);
        QRect rect(start_sample/zoomRatio,0,(end_sample-start_sample)/zoomRatio,height());
        setChanged(rect);
        update();
    }
}



/*!
    \fn WaveCanvas::changeViewMode(int)

    changes the view mode and forces the repaint


 */
void WaveCanvas::changeViewMode(int vm)
{
    viewMode=vm<=1?vm:0;
    forceRepaint();
}


/*!
    \fn WaveCanvas::drawWave(long,long)

    draws the wave in amplitude domain from start_sample to end_sample and stores the pixmap

 */
void WaveCanvas::drawWave(long start_sample,long end_sample)
{
    //QProgressDialog progress("Drawing wave...",NULL,end_sample-start_sample,NULL,"progress",TRUE);
    //progress.setMinimumDuration(1500);
    cout<<"Drawing from "<<start_sample<<" to "<<end_sample<<"\n";
    if(soundManager && soundManager->hasSound()&&
       zoomRatio>=1 && width()>0 && height()>0){
            
            float* leftAudio=soundManager->getLeftChannel(SoundHolder::FOR_OUTPUT);
            float* rightAudio=soundManager->getRightChannel(SoundHolder::FOR_OUTPUT);
            
            QPointArray rmsPolygonL;
            QPointArray rmsPolygonR;
            long jump=zoomRatio;
            if(jump<1) jump=1;
            if(start_sample<0)start_sample=0;
            if(end_sample>=soundManager->getFrames()) end_sample=soundManager->getFrames()-jump;
            bool wasEmpty=TRUE;
            int v_height=height()-getRulerHeight();
            int v_width=int(ceil((end_sample-start_sample)/float(zoomRatio)));
            int c_x=0;
            if(v_width<1) return;
            if(!backgroundPix){
                backgroundPix=new QPixmap(v_width,height());
            }
            else if(backgroundPix->width()!=v_width || backgroundPix->height()!=height()){
                        backgroundPix->resize(v_width,height());
            }else{
                wasEmpty=FALSE;
            }
            QPainter localpainter(backgroundPix);
            localpainter.fillRect(backgroundPix->rect(),QBrush(bgColor));


            QColor wavecolor(50,50,255);
            QColor rmscolor(255,0,0);
            QPen wavepen(wavecolor,1);
            QPen rmspen(rmscolor,1);
            //RasterOp waveRop=localpainter.rasterOp();
            //RasterOp rmsRop=Qt::AndROP;
            int translate=0;
            if(_hasRuler /*&& wasEmpty*/){

                QFont font;
                font.setPixelSize(8);
                localpainter.setFont(font);
                localpainter.fillRect(0,0,v_width,getRulerHeight(),QBrush(lightGray));
                localpainter.setPen(black);
                localpainter.drawLine(0,getRulerHeight(),v_width,getRulerHeight());
                int ticksDistance=(maxZoomRatio/zoomRatio)*10;
                int midTicksDistance=ticksDistance/2;
                int mid=0;
                QString number="";
                int count=0;
                int nbTicksToOrigin=0;
                if(pixmapXOrigin!=0 && ticksDistance!=0){
                    nbTicksToOrigin=pixmapXOrigin%ticksDistance;
                    for (int i=ticksDistance-nbTicksToOrigin;
                                i<v_width;i+=ticksDistance){
                        if(i<v_width)
                            localpainter.drawLine(i,0,i,getRulerHeight()-4);
                        mid=i+midTicksDistance;
                        if(mid<v_width){
                            localpainter.drawLine(mid,0,mid,getRulerHeight()/2);
                        }
                        /*
                        if(count%(v_width/10)==0){
                            number=QString::number(start_sample+(i*zoomRatio));
                            localpainter.drawText(i,getRulerHeight()/2+2,number);
                        }
                        */
                    }
                }
                translate=translate+getRulerHeight();
                count++;
            }

            /*if(!wasEmpty) translate=translate+getRulerHeight();*/
            //end drawRuler
            translate=int(translate+(double)v_height/4.0);
            int x=c_x;
            //float sampleHeightFactor=(0.8/SHRT_MAX)*(v_height/4);
            float sampleHeightFactor=0.8*(v_height/4);
            
            if(!leftMaximaBuffer || !rightMaximaBuffer){
                 //oh some caches..ya know..
                leftMaximaBuffer=new maxAndMin[(int)ceil(soundManager->getFrames()/jump)];
                rightMaximaBuffer=new maxAndMin[(int)ceil(soundManager->getFrames()/jump)];
                for (int i=0;i<(int)ceil(soundManager->getFrames()/jump);i++){
                    leftMaximaBuffer[i].hasValue=0;
                    rightMaximaBuffer[i].hasValue=0;
                }
                maxBufferNbValues=(int)ceil(soundManager->getFrames()/jump);
            }
            rms_env_reset(rmsL);
            rms_env_reset(rmsR);
            bool rmsprefilled=FALSE;
            int reminder=(end_sample-start_sample) % jump;
            bool drawRMS=jump<4096;
            for (int i=start_sample;i<end_sample-reminder;i=i+jump){
                    float maxL=0;
                    float minL=0;
                    float maxR=0;
                    float minR=0;
                    float maxRMSL=0;
                    float maxRMSR=0;
                    float maxRMSLbefore=0;
                    float maxRMSRbefore=0;
                    if(!leftMaximaBuffer[i/zoomRatio].hasValue ||!rightMaximaBuffer[i/zoomRatio].hasValue){
                        if(!rmsprefilled && start_sample>RMS_BUF_SIZE){
                            //prefilling the rms buffer
                            for (int i2=i-RMS_BUF_SIZE;i2<i;i2++){
                                float valL=leftAudio[i2];
                                float valR=rightAudio[i2];
                                rms_env_process(rmsL,valL);
                                rms_env_process(rmsR,valR);
                            }
                            rmsprefilled=TRUE;
                        }
                        float valL=0;
                        float valR=0;
                        float rmsvalL=0;
                        float rmsvalR=0;
                        for (int j=i;j<i+jump;j++){
                            valL=leftAudio[j];
                            valR=rightAudio[j];
                            if(drawRMS){
                                rmsvalL=rms_env_process(rmsL,valL);
                                rmsvalR=rms_env_process(rmsR,valR);
                            }
                            if(valL>=0){
                                if(valL>maxL) maxL=valL;
                            }else if(valL<=0){
                                if(valL<minL) minL=valL;
                            }
                            if(valR>=0){
                                if(valR>maxR) maxR=valR;
                            }else if(valR<=0){
                                if(valR<minR) minR=valR;
                            }
                            
                            if(drawRMS){
                                if(rmsvalL>maxRMSL) maxRMSL=rmsvalL;
                                if(rmsvalR>maxRMSR) maxRMSR=rmsvalR;
                            }
                        }

                        leftMaximaBuffer[i/jump].min=minL;
                        leftMaximaBuffer[i/jump].max=maxL;
                        leftMaximaBuffer[i/jump].rms=maxRMSL;
                        leftMaximaBuffer[i/jump].hasValue=1;
                        
                        rightMaximaBuffer[i/jump].min=minR;
                        rightMaximaBuffer[i/jump].max=maxR;
                        rightMaximaBuffer[i/jump].rms=maxRMSR;
                        rightMaximaBuffer[i/jump].hasValue=1;
                    }else{
                        minL=leftMaximaBuffer[i/jump].min;
                        maxL=leftMaximaBuffer[i/jump].max;
                        maxRMSL=leftMaximaBuffer[i/jump].rms;
                        
                        minR=rightMaximaBuffer[i/jump].min;
                        maxR=rightMaximaBuffer[i/jump].max;
                        maxRMSR=rightMaximaBuffer[i/jump].rms;
                        
                    }
                    maxRMSLbefore=i>0?leftMaximaBuffer[(i-1)/jump].rms:0;
                    maxRMSRbefore=i>0?rightMaximaBuffer[(i-1)/jump].rms:0;

                    //if(hasPixmapV) return; //avoid cascading redraws
                    localpainter.setPen(wavepen);
                    //localpainter.setRasterOp(waveRop);

                    localpainter.drawLine(x,(int)((float)-minL*sampleHeightFactor)+translate,x,(int)((float)-maxL*sampleHeightFactor)+translate);
                    localpainter.drawLine(x,(int)((float)-minR*sampleHeightFactor)+translate+int((double)v_height/2.0),
                                          x,(int)((float)-maxR*sampleHeightFactor)+translate+int((double)v_height/2.0));

                    localpainter.setPen(rmspen);
                    //localpainter.setRasterOp(rmsRop);
                    if(x==0){
                        localpainter.drawPoint(x,(int)((float)-maxRMSL*sampleHeightFactor)+translate);
                        localpainter.drawPoint(x,(int)((float)-maxRMSR*sampleHeightFactor)+translate+int((double)v_height/2.0));
                        
                        localpainter.drawPoint(x,(int)((float)+maxRMSL*sampleHeightFactor)+translate);
                        localpainter.drawPoint(x,(int)((float)+maxRMSR*sampleHeightFactor)+translate+int((double)v_height/2.0));
                    }else{
                         /*
                        rmsPolygonL.putPoints(0,4,
                                    x,(int)((float)-maxRMSL*sampleHeightFactor)+translate,
                                    x-1,(int)((float)-maxRMSLbefore*sampleHeightFactor)+translate,
                                    x,(int)((float)+maxRMSL*sampleHeightFactor)+translate,
                                    x-1,(int)((float)+maxRMSLbefore*sampleHeightFactor)+translate);
                                                    
                        rmsPolygonR.putPoints(0,4,
                                    x,(int)((float)-maxRMSR*sampleHeightFactor)+translate+(double)v_height/2.0,
                                    x-1,(int)((float)-maxRMSRbefore*sampleHeightFactor)+translate+(double)v_height/2.0,
                                    x,(int)((float)+maxRMSR*sampleHeightFactor)+translate+(double)v_height/2.0,
                                    x-1,(int)((float)+maxRMSRbefore*sampleHeightFactor)+translate+(double)v_height/2.0);
                        
                        
                           localpainter.drawPolygon(rmsPolygonL,TRUE);
                           localpainter.drawPolygon(rmsPolygonR,TRUE);
                           */
                        if(drawRMS){
                            localpainter.drawLine(x,(int)((float)-maxRMSL*sampleHeightFactor)+translate,
                                            x-1,(int)((float)-maxRMSLbefore*sampleHeightFactor)+translate);
                            localpainter.drawLine(x,(int)((float)-maxRMSR*sampleHeightFactor)+translate+int((double)v_height/2.0),
                                            x-1,(int)((float)-maxRMSRbefore*sampleHeightFactor)+translate+int((double)v_height/2.0));
                        }
                        
                        /*
                        localpainter.drawLine(x,(int)((float)+maxRMSL*sampleHeightFactor)+translate,
                                        x-1,(int)((float)+maxRMSLbefore*sampleHeightFactor)+translate);
                        localpainter.drawLine(x,(int)((float)+maxRMSR*sampleHeightFactor)+translate+(double)v_height/2.0,
                                        x-1,(int)((float)+maxRMSRbefore*sampleHeightFactor)+translate+(double)v_height/2.0);
                          */
                    }

                    x++;
                    /*
                    if((i-start_sample)%jump==0){
                        progress.setProgress(i);
                        progress.setLabelText("Drawing wave...(frame: "+QString::number(i)+")");
                        //mainApplication->wakeUpGuiThread();
                        cout<<"progress\n";
                    }
                    */
            }
            hasPixmapV=TRUE;
            cout<<"end drawing\n";
    }
}


/*!
    \fn WaveCanvas::drawSpectrum(long,long)

    draws the wave as spectrogram from start_sample to end_sample and stores the pixmap
 */
void WaveCanvas::drawSpectrum(long start_sample,long end_sample)
{

    std::cout<<"start drawing spectrum\n";
    QColor color(0,255,0);
    int nbbands=soundManager->getHiresFreqNbBands();
    float** subband_energies=soundManager->getHiresFreqSubbandEnergies();
    float minima=soundManager->getHiresFreqFFTMinima();
    float maxima=soundManager->getHiresFreqFFTMaxima();
    float maximaLog=10*log10(maxima);
    float minimaLog=minima==0?0:10*log10(minima);
    float spectralMeanOverFrames=(maximaLog-minimaLog)/2;
    int fftAdvance=soundManager->getHiresFreqFFTAdvance();

/*
     QProgressDialog progress("Drawing spectrum...",NULL,end_sample-start_sample,NULL,"progress",TRUE);
     progress.setMinimumDuration(2000);
     progress.setProgress(0);
*/
     if(soundManager!=0 && soundManager->hasSound()&& zoomRatio>=1){
            long jump=zoomRatio;
            if(jump<1) jump=1;
            if(jump<fftAdvance) jump=fftAdvance;
            if(start_sample<0)start_sample=0;
            if(end_sample>=soundManager->getFrames()) end_sample=soundManager->getFrames();
            int v_height=height()-getRulerHeight();
            int v_width=int(ceil((end_sample-start_sample)/float(zoomRatio)));
            int c_x=0;

           if(!backgroundPix){
                backgroundPix=new QPixmap(v_width,height());
            }
            else if(backgroundPix->width()!=v_width || backgroundPix->height()!=height()){
                        backgroundPix->resize(v_width,height());
            }
            QPainter localpainter(backgroundPix);
            QFont font;
            font.setPixelSize(8);
            localpainter.setFont(font);
            localpainter.fillRect(backgroundPix->rect(),QBrush(bgColor));



            int translate=0;
           if(_hasRuler){
                localpainter.fillRect(0,0,v_width,getRulerHeight(),QBrush(lightGray));
                localpainter.setPen(black);
                localpainter.drawLine(0,getRulerHeight(),v_width,getRulerHeight());
                int ticksDistance=(maxZoomRatio/zoomRatio)*10;
                int midTicksDistance=ticksDistance/2;
                int mid=0;
                QString number="";
                int count=0;
                 if(pixmapXOrigin!=0 && ticksDistance!=0){
                    for (int i=ticksDistance-(pixmapXOrigin%ticksDistance);
                                i<v_width;i+=ticksDistance){
                        if(i<v_width)
                            localpainter.drawLine(i,0,i,getRulerHeight()-4);
                        mid=i+midTicksDistance;
                        if(mid<v_width){
                            localpainter.drawLine(mid,0,mid,getRulerHeight()/2);
                        }
                        /*
                        if(count%(v_width/10)==0){
                            number=QString::number(start_sample+(i*zoomRatio));
                            localpainter.drawText(i,getRulerHeight()/2+2,number);
                        }
                        */
                    }
                }
                translate=translate+getRulerHeight();
                count++;
            }
            /*if(!wasEmpty) translate=translate+getRulerHeight();*/
            //end drawRuler

            int x=c_x;
            float bandHeightFactor=float(v_height)/float(nbbands);
            float bandWidthFactor=float(fftAdvance)/float(zoomRatio);
            MyMath::smartRoundSum bwFactorRound;
            bwFactorRound.init(bandWidthFactor);
            MyMath::smartRoundSum bhFactorRound;
            bhFactorRound.init(bandHeightFactor);
            std::cout<<"band height factor: "<<bandHeightFactor<<" band width factor:"<<bandWidthFactor<<"\n";
            std::cout<<"jump: "<<jump<<"\n";
            float max=FLT_MIN;
            float val=0;
            int colorValue=0;
            QWMatrix matrix=localpainter.worldMatrix();
            matrix.translate(0,translate);
            localpainter.setWorldMatrix(matrix);

            //oh, some caches..
            if(!spectrogramMaxBuffer){
                spectrogramMaxBuffer=
                        new spectrogramMax[(int)ceil(soundManager->getFrames()/jump)];
                spectrogramMaxBufferNbValues=(int)ceil(soundManager->getFrames()/jump);
                for (int i=0;i<(int)ceil(soundManager->getFrames()/jump);i++){
                    spectrogramMaxBuffer[i].hasValue=0;
                    spectrogramMaxBuffer[i].max=new float[nbbands];
                }
            }
            int roundoff=0;
            float test_roundoff=0;
            int lastchunk=end_sample+jump>soundManager->getFrames()?
                                        soundManager->getFrames()%jump:0;
            cout<<"Last chunk: "<<lastchunk<<"\n";
            int remider=(end_sample-start_sample) % jump;
            for (int i=start_sample;i<end_sample-remider;i=i+jump){
                    bwFactorRound.myround();
                    int y=0;
                    bhFactorRound.init(bandHeightFactor);
                    //cout<<"i: "<<i<<" jump: "<<jump<<"\n";
                    for(int band=0;band<nbbands;band++){
                        bhFactorRound.myround();
                        max=FLT_MIN;
                        if(!spectrogramMaxBuffer[i/jump].hasValue){
                            for (int j=i;j<=i+jump;j=j+fftAdvance){
                                        //cout<<"nbbands: "<<nbbands<<" j:"<<j<<" fa: "<<fftAdvance<<" band: "<<band<<"\n";
                                        val=subband_energies[nbbands-1-band][j/fftAdvance];
                                        if(val>max) max=val;
                            }
                            if(soundManager->getSubstractSpectralMean())
                                max=10*log10(max)-spectralMeanOverFrames;
                            else
                                max=10*log10(max);
                            spectrogramMaxBuffer[i/jump].max[band]=max;
                            if(band==nbbands-1) spectrogramMaxBuffer[i/jump].hasValue=1;
                        }else{
                            max=spectrogramMaxBuffer[i/jump].max[band];
                        }

                        colorValue=int(MyMath::linear_regression(minimaLog,maximaLog,255,0,max));
                        colorValue=colorValue>255?255:colorValue<0?0:colorValue;
                        //color.setRgb(colorValue,colorValue,colorValue);
                        color.setHsv(colorValue,255,255);
                        if(colorValue!=0){
                            localpainter.setPen(color);
                            if(bandHeightFactor<=1.0 && bandWidthFactor<=1.0){
                                localpainter.drawPoint(x,int(band*bandHeightFactor));
                            }else if (bandHeightFactor>1.0 && bandWidthFactor<=1.0){
                                localpainter.drawLine(x,y,x,bhFactorRound.rounded());
                            }else if(bandWidthFactor>1.0 && bandHeightFactor<=1.0){
                                if(x!=x+bwFactorRound.rounded()){
                                    localpainter.drawLine(x,int(band*bandHeightFactor),
                                            bwFactorRound.rounded(),int(band*bandHeightFactor));
                                }
                            }else{
                                localpainter.setBrush(QBrush(color));
                                localpainter.fillRect(x,y,
                                        bwFactorRound.rounded()-x,bhFactorRound.rounded()-y,QBrush(color));
			    }
                         }
                         if(bandHeightFactor<=1){
                             y++;
                         }else{
                             y=bhFactorRound.rounded();
                         }
                    }
                    if(bandWidthFactor<=1){
                        x++;
                        roundoff++;
                    }else{
                        test_roundoff+=bandWidthFactor;
                        roundoff=bwFactorRound.rounded();
                        x=c_x+bwFactorRound.rounded();//ceil(bandWidthFactor);
                        /*
                        cout<<"value: "<<bandWidthFactor<<" rounded to: "<<bwFactorRound.rounded()<<" total: "<<roundoff<<" should be: "<<test_roundoff<<"\n";
                        */

                    }
/*
                    if((i-start_sample)%(jump*100)==0){
                        progress.setProgress(i-start_sample);
                        progress.setLabelText("Drawing spectrum...(frame: "+QString::number(i)+")");
                        mainApplication->processEvents();
                    }
*/
            }
            if(lastchunk>0){
                localpainter.fillRect(x,0,v_width-c_x-x,v_height,QBrush(blue));
            }
            font.setPixelSize(12);
            font.setWeight(QFont::Bold);
            localpainter.setPen(black);
            localpainter.setFont(font);
            QFontMetrics font_metrics(font);
            QString highFreqText=
                    QString::number(soundManager->getHiresFreqEndFreq())+" Hz";
            QString lowFreqText=
                    QString::number(soundManager->getHiresFreqStartFreq())+" Hz";
            QString middleFreqText=
                    QString::number(soundManager->getHiresFreqStartFreq()+
                    (soundManager->getHiresFreqEndFreq()-
                    soundManager->getHiresFreqStartFreq())/2)+" Hz";
            localpainter.drawText(c_x,font_metrics.height(),highFreqText);
            localpainter.drawText(c_x+v_width/2,font_metrics.height(),highFreqText);
            localpainter.drawText(c_x+v_width-font_metrics.width(highFreqText),
                                                    font_metrics.height(),highFreqText);

            localpainter.drawText(c_x,v_height/2,middleFreqText);
            localpainter.drawText(c_x+v_width/2,v_height/2,
                                  middleFreqText);
            localpainter.drawText(c_x+v_width-font_metrics.width(lowFreqText),
                                  v_height/2,middleFreqText);

            localpainter.drawText(c_x,v_height-font_metrics.height(),lowFreqText);
            localpainter.drawText(c_x+v_width/2,v_height-font_metrics.height(),
                                                    lowFreqText);
            localpainter.drawText(c_x+v_width-font_metrics.width(lowFreqText),
                                  v_height-font_metrics.height(),lowFreqText);
            hasPixmapV=TRUE;
            cout<<"real width: "<<v_width<<" rounded width: "<<roundoff<<"\n";
    }
    std::cout<<"end drawing spectrum\n";
}




/*!
    \fn WaveCanvas::setPixmapXOrigin(int)

    sets the origin of the pixmap. Used when repainting only the part of the image.
    \sa pixmapXOrigin
 */
void WaveCanvas::setPixmapXOrigin(int x_orig)
{
    pixmapXOrigin=x_orig;
}


/*!
    \fn WaveCanvas::hasPixmap()

    \return  is the pixmap is already computed?
 */
bool WaveCanvas::hasPixmap()
{
    return hasPixmapV;
}


/*!
    \fn WaveCanvas::zapBuffers()
 */
void WaveCanvas::zapBuffers()
{
    //cout<<"in wavecanvas (parent ["<<parent()->parent()->name()<<"]) started zapping wave canvas buffers\n";
    if (leftMaximaBuffer) zaparr(leftMaximaBuffer);
    if (rightMaximaBuffer) zaparr(rightMaximaBuffer);

    if (spectrogramMaxBuffer){
        for (int i=0;i<spectrogramMaxBufferNbValues;i++){
            if (spectrogramMaxBuffer[i].max){
                zaparr(spectrogramMaxBuffer[i].max);
                spectrogramMaxBuffer[i].hasValue=FALSE;
            }
        }
        spectrogramMaxBufferNbValues=0;
        if(spectrogramMaxBuffer) zaparr(spectrogramMaxBuffer);
    }
    cout<<"in wavecanvas (parent ["<<parent()->parent()->name()<<"]) Buffers zapped\n";
}


/*!
    \fn WaveCanvas::zapBuffers(long start, long end)
 */
void WaveCanvas::zapBuffers(long start, long end)
{
    for (int i=start/zoomRatio;i<end/zoomRatio;i++){
        if (leftMaximaBuffer && &leftMaximaBuffer[i]) leftMaximaBuffer[i].hasValue=0;
        if (rightMaximaBuffer && &rightMaximaBuffer[i]) rightMaximaBuffer[i].hasValue=0;
        if (spectrogramMaxBuffer && &spectrogramMaxBuffer[i]) spectrogramMaxBuffer[i].hasValue=0;
    }
    cout<<"in wavecanvas (parent ["<<parent()->parent()->name()<<"]) Buffers cleaned\n";
}



/*!
    \fn WaveCanvas::setVisibleWidth(int w)
    Sets the with of the displayed part of the canvas.
 */
void WaveCanvas::setVisibleWidth(int w)
{
    visibleWidth=w;
}


/*!
    \fn WaveCanvas::emptyBuffers()
    Flushes the buffers containing max and min values for amplitude and spectrogram drawing.
 */

void WaveCanvas::emptyBuffers()
{

    for (int i=0;i<maxBufferNbValues;i++){
        leftMaximaBuffer[i].hasValue=0;
        rightMaximaBuffer[i].hasValue=0;
    }
    for (int i=0;i<spectrogramMaxBufferNbValues;i++){
            spectrogramMaxBuffer[i].hasValue=FALSE;
    }
}


void WaveCanvas::setMainApplication(QApplication* theValue) {
    mainApplication = theValue;
}
