/***************************************************************************
 *   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 "drawsoundwidget.h"
#include <qpixmap.h>
#include <qpainter.h>
#include <qcanvas.h>
#include <sndfile.h>
#include <qmutex.h>
#include <limits>
#include <float.h>
#include <iostream>
#include <qmemarray.h>
#include <beatline.h>
#include <selectionrectangle.h>
#include <qvaluelist.h>
#include <list>
#include <qpen.h>
#include <qdragobject.h>


DrawSoundWidget::DrawSoundWidget(QWidget *parent, const char *name,SoundManager* sm)
 : DrawSoundWidgetAbstract(parent, name,sm)
{
        this->setDragAutoScroll(TRUE);
        viewport()->setMouseTracking(TRUE);
        //this->setMouseTracking(TRUE);
        QMutex mutex(TRUE);
        selection=new SelectionRectangle(0,
                0,20,0,canvas->height()-20,canvas,TRUE);
        selection->hide();

        lockedBeatRects.setAutoDelete(TRUE);

        playline=new PlayLine(canvas,0);
	QPen* pen =new QPen();
	pen->setWidth(1);
	pen->setColor(QColor(200,0,0));

        playline->setPen(*pen);
        playline->setPoints(0,0,0,visibleHeight());
        playline->setZ(-2);
        playline->show();


        loopMarkerL=new LoopMarker(canvas,LoopMarker::LEFT_MARKER);
        loopMarkerR=new LoopMarker(canvas,LoopMarker::RIGHT_MARKER);
        measureMarker=new MeasureMarker(canvas,loopMarkerL,loopMarkerR);
        canvas->setBgColor(240,255,255);
        canvas->hasRuler(TRUE);
        //canvas->update();



        computed_bpm=0;
        computedBPMModifier=1;
        new_to_oldBPM_ratio=1;
        playPosition=0;
        treshold=20;
        windowDivider=4;
        connect(this,SIGNAL(contentsMoving(int,int)),SLOT(contentsMoved(int,int)));
        connect(soundManager,SIGNAL(newBeatLineAvailable(long)),
                         SLOT(addBeatLine(long)));
        connect(soundManager,SIGNAL(analysisFinished()),SLOT(analysisFinished()));

        showBeatLinesVal=TRUE;
        savedRelativeSamplePos=0;  //tracks mouse click inside view area

        sampleValueView=new SampleValueView(soundManager,canvas);
        sampleValueView->hide();
        setAcceptDrops(TRUE);
        scrollTimer = new QTimer( this );
        scrollTimer->stop();
        connect(scrollTimer, SIGNAL(timeout()),this, SLOT(scroll()));

        keyboardView=new KeyboardView(canvas);
        keyboardView->hide();
}

 void DrawSoundWidget::contentsMousePressEvent( QMouseEvent * mouseEvent){
        QPoint pos=mouseEvent->pos();
        //remove keyboard view if not clicked
        if(keyboardView->isVisible() && !keyboardView->rect().contains(pos)){
            keyboardView->hide();
        }
        
        
        int pos_x=pos.x();
        long sample_pos=pos.x()*getZoomRatio();
        if(selection->isVisible())
            savedRelativeSamplePos=sample_pos-selection->getStartSamplePosition();
        // magnet selection line
        int temp_pos_x=0;
        long temp_sample_pos=0;
        this->getNearestLinePos(pos,temp_sample_pos,temp_pos_x);
        if(fabs(pos.x()-temp_pos_x)<50){
            sample_pos=temp_sample_pos;
            pos_x=temp_pos_x;
        }
        // end magnet selection line
        if (mouseEvent->button()==RightButton){
                if(mouseEvent->state() & ControlButton){
                    loopMarkerR->setSamplePosition(sample_pos);
                    loopMarkerR->setX(pos_x);
                    if (*loopMarkerR<loopMarkerL) swapMarkers();
                    measureMarker->setBeatWidth(int(getBeatDistance()/getZoomRatio()));
                    measureMarker->show();
                    loopMarkerR->setMoving(TRUE);
                    canvas->update();
                }else if(mouseEvent->pos().y()<canvas->getRulerHeight()){
                    emit(playFromTo(findLeftBeatline(sample_pos),findRightBeatline(sample_pos)));
                }else if(BeatLine* beatline=getMovableBeatLine(mouseEvent->pos())){
                    beatline->setMoving(TRUE);
                    canvas->setAllChanged();
                    canvas->update();
                }else if(BeatLine* beatline=getRemovableBeatLine(mouseEvent->pos())){
                    soundManager->removeBeatLineAt(beatline->getBeatPos());
                    beatLines.remove(beatline);
                    delete beatline;
                    canvas->update();
                }else if(BeatLine* beatline=getLockableBeatLine(mouseEvent->pos())){
                    if(beatline->locked()){
                                    beatline->unlock();
                                    if(beatline->isBpmLine())
                                            bpmLines.append(beatline);
                                    else
                                            beatLines.append(beatline);
                                    lockedBeatLines.remove(beatline);
                                    if(lockedBeatLines.count()==0)
                                        emit(hasLockedBeatLines(FALSE));

                            }else{
                                    beatline->lock();
                                    lockedBeatLines.append(beatline);
                                    if(lockedBeatLines.count()==1)
                                        emit(hasLockedBeatLines(TRUE));
                                    if(beatline->isBpmLine())
                                            bpmLines.remove(beatline);
                                    else
                                            beatLines.remove(beatline);
                            }
                            updateBeatLines();
                            updateLockedBeatRects();
                            emit(beatLinesChanged(toArray(beatLines)));
                            emit(lockedBeatLinesChanged(toArray(lockedBeatLines)));
                }else if(BeatLine* beatline=getAssignableBeatLine(mouseEvent->pos())){
                    keyboardView->setX(beatline->x());
                    keyboardView->setY(canvas->height()-30);
                    keyboardView->show();
                    canvas->update();
                }else if(LockedBeatRect* beatrect=getMovableBeatRect(mouseEvent->pos())){
                    beatrect->setSelected(TRUE);
                    canvas->update();
                }else{
                    QCanvasItemList colisions=canvas->collisions(pos);
                    /*
                    if(!colisions.isEmpty() && colisions.first()->rtti()==9){
                            BeatLine* temp=(BeatLine*)colisions.first();
                            if(temp->locked()){
                                    temp->unlock();
                                    if(temp->isBpmLine())
                                            bpmLines.append(temp);
                                    else
                                            beatLines.append(temp);
                                    lockedBeatLines.remove(temp);
                            }else{
                                    temp->lock();
                                            lockedBeatLines.append(temp);
                                    if(temp->isBpmLine())
                                            bpmLines.remove(temp);
                                    else
                                            beatLines.remove(temp);
                            }
                            updateBeatLines();
                    }else*/ if(!colisions.isEmpty() &&
                                        colisions.first()->rtti()==RTTI_LOOPMARKER){
                                cout<<"loop marker hit bw: "<<int(getBeatDistance()/getZoomRatio())<<endl;
                            LoopMarker* temp=(LoopMarker*)colisions.first();
                            temp->setMoving(TRUE);
                            measureMarker->setBeatWidth(int(getBeatDistance()/getZoomRatio()));
                            measureMarker->setActive(TRUE);
                            measureMarker->show();
                            canvas->setAllChanged();
                            canvas->update();
                    }
            }
    }else if (mouseEvent->button()==LeftButton){
            if(mouseEvent->state() & ControlButton){
                    //move loop markers
                    loopMarkerL->setSamplePosition(sample_pos);
                    loopMarkerL->setX(pos_x);
                    if (*loopMarkerR<loopMarkerL) swapMarkers();
                    measureMarker->setBeatWidth(int(getBeatDistance()/getZoomRatio()));
                    measureMarker->show();
                    loopMarkerL->setMoving(TRUE);
                    canvas->update();
            }else if(mouseEvent->pos().y()<canvas->getRulerHeight()){
                //left-click in the ruler -> play from point
                emit(playFromPoint(sample_pos));
            }else if(mouseEvent->state() & ShiftButton){
                //vertical selection
                if(!verticalSelections.isEmpty() &&
                                 mouseEvent->pos().y()>verticalSelections.first()->y()-20 &&
                                 mouseEvent->pos().y()<verticalSelections.first()->y()+abs(verticalSelections.first()->height())+20
                        ){
                     //moving selection
                    //savedRelativeSamplePos=sample_pos-selections.first()->getStartSamplePosition();
                     //verticalSelections.first()->setMoving(true);
                     cout<<"moving set\n";
                 }else{
                     /*
                    verticalSelections.clear();
                    int start_band_pos=int(((canvas->height()-mouseEvent->pos().y())*512.0)/canvas->height());
                    VerticalSelectionRectangle* sel=
                        new VerticalSelectionRectangle(soundManager, start_band_pos,
                                                                    contentsX(),mouseEvent->pos().y(),canvas->width(),0,canvas,TRUE);
                    sel->setResizing(TRUE);
                    sel->show();
                    verticalSelections.append(sel);
                    canvas->update();
                     */
                }
            }else{
                //handle selections
                if(selection->isVisible() &&
                                 selection->getCenterRect()->contains(mouseEvent->pos())){
                     //moving selection
                    cout<<"moving selection\n";
                    savedRelativeSamplePos=sample_pos-selection->getStartSamplePosition();
                     selection->setMoving(true);
                 }else if(selection->isVisible() &&
                                  selection->getLeftRect()->contains(mouseEvent->pos().x(),
                                                                                                             mouseEvent->pos().y())){
                     selection->setLeftSideResizing(true);
                 }else if(selection->isVisible() &&
                                  selection->getRightRect()->contains(mouseEvent->pos().x(),
                                                                                                                 mouseEvent->pos().y())){
                     selection->setResizing(true);
                 }else{
                    selection->init(sample_pos,pos_x,20,0,canvas->height()-20);
                    selection->show();
                    selection->setResizing(TRUE);
                }
        }
    }
 }

    void DrawSoundWidget::contentsMouseMoveEvent( QMouseEvent * mouseEvent){
        checkAndScroll(mouseEvent);
        handleMouseMoveBeatLine(mouseEvent);
        handleMouseMoveSelectionRectangles(mouseEvent);
        handleMouseMoveVerticalSelectionRectangles(mouseEvent);
        handleMouseMoveLoopMarkers(mouseEvent);
        handleMouseMoveBeatRect(mouseEvent);
    }
 void DrawSoundWidget::contentsMouseReleaseEvent( QMouseEvent * mouseEvent){
    scrollTimer->stop();
    if (mouseEvent->button()==LeftButton){
        if(mouseEvent->pos().y()<canvas->getRulerHeight()){
            emit(stopPlay());
        }else{
                    selection->setResizing(FALSE);
                    selection->setLeftSideResizing(FALSE);
                    selection->setMoving(FALSE);
                    if (abs(selection->width())<5){
                            removeSelectionRectangles();
                    }
            if(!verticalSelections.isEmpty()){
                    verticalSelections.first()->setResizing(FALSE);
                    verticalSelections.first()->setLeftSideResizing(FALSE);
                    verticalSelections.first()->setMoving(FALSE);
                    if (abs(verticalSelections.first()->height())<5){
                            verticalSelections.remove(verticalSelections.first());
                            canvas->update();
                    }
            }
            //printf("selections count: %d\n",selections.count());
        }
    }
    if(loopMarkerL->getMoving()){
        loopMarkerL->setMoving(FALSE);
        measureMarker->hide();
        emit(loopChange());
        canvas->update();
    }
    if(loopMarkerR->getMoving()){
        loopMarkerR->setMoving(FALSE);
        measureMarker->hide();
        emit(loopChange());
        canvas->update();
    }
    if(BeatLine* beatline=getMovingBeatLine()) beatline->setMoving(FALSE);
    if(LockedBeatRect* beatrect=getMovingBeatRect()) beatrect->setSelected(FALSE);
    setCursor(QCursor(Qt::Qt::ArrowCursor ));
    canvas->update();
 }


void DrawSoundWidget::resized(){
    updateCanvas=false;
    setPositionPointer((int)((double)playPosition/getZoomRatio()));
    updateLoopMarkers();
    updateSelectionRectangles();
    updateBeatLines();
    updateLockedBeatRects();
    updateCanvas=true;
    canvas->update();
}

/*!
    \fn DrawSoundWidget::fileLoaded(double,double,SF_INFO)
 */
void DrawSoundWidget::fileLoaded()
{
    setPositionPointer(0);
    unlockBeatLines();
    removeBeatLines();
    removeBPMLines();
    setBeatLines(soundManager->analyse(16,4));
    analysisFinished();
    setLoopMarkersOnMeasure(0);
    loopMarkerL->show();
    loopMarkerR->show();
    removeSelectionRectangles();
}



DrawSoundWidget::~DrawSoundWidget()
{
}







/*!
    \fn DrawSoundWidget::getPositionPointerCI()
 */
PlayLine* DrawSoundWidget::getPositionPointerCI()
{
    return playline;
}


/*!
    \fn DrawSoundWidget::setPositionPointer(int)
 */
void DrawSoundWidget::setPositionPointer(long _pos)
{
    if(_pos>0 && _pos<soundManager->getFrames()){
        playPosition=_pos;
        getPositionPointerCI()->setX(playPosition/getZoomRatio());
        getPositionPointerCI()->setPosition(playPosition);
        if(updateCanvas) canvas->update();
    }
}




void DrawSoundWidget::removeBeatLines()
{
        QPtrListIterator<BeatLine> it( beatLines );
        BeatLine *beatline;
        while ( (beatline = it.current()) != 0 ) {
                ++it;
                beatLines.remove(beatline);
                delete beatline;
        }
        if(updateCanvas) canvas->update();
        emit(beatLinesChanged(toArray(beatLines)));
}

void DrawSoundWidget::addBeatLine(long beat){
    bool alreadyPresent=FALSE;
    QPtrListIterator<BeatLine> it( lockedBeatLines );
    BeatLine *beatline;
    while ( (beatline = it.current()) != 0 ) {
        ++it;
        if(abs(beatline->getBeatPos()-beat)<16){
            //cout<<"Already present: "<<beatline->getBeatPos()<<endl;
            alreadyPresent=TRUE;
            break;
        }
    }
    if(!alreadyPresent){
            BeatLine* beatline=new BeatLine(canvas,beat);
            beatline->setSampleValueView(sampleValueView);
            beatline->setPen(QColor(50,255,50));
            beatline->setX((int)((double)beat/getZoomRatio()));
            if(showBeatLinesVal) beatline->show();
            beatLines.append(beatline);
            emit(beatLinesChanged(toArray(beatLines)));
    }

}

void DrawSoundWidget::addLockedBeatLine(long beat){
    //locks the beatline if already present
    bool alreadyPresent=FALSE;
    QPtrListIterator<BeatLine> it( beatLines );
    BeatLine *beatline;
    while ( (beatline = it.current()) != 0 ) {
        ++it;
        if(abs(beatline->getBeatPos()-beat)<16){
            beatline->lock();
            lockedBeatLines.append(beatline);
            beatLines.remove(beatline);
            alreadyPresent=TRUE;
            break;
        }
    }
    if(!alreadyPresent){
        BeatLine* beatline=new BeatLine(canvas,beat);
        beatline->setSampleValueView(sampleValueView);
        beatline->setPen(QColor(50,255,50));
        beatline->setX((int)((double)beat/getZoomRatio()));
        beatline->lock();
        if(showBeatLinesVal) beatline->show();
        lockedBeatLines.append(beatline);
    }

}



/*!
    \fn DrawSoundWidget::setBeatLines(QMemArray<BeatLine>*)
 */
void DrawSoundWidget::setBeatLines(QMemArray<long> beats)
{
        removeBeatLines();
        beats.sort();
        for (uint i=0;i<beats.size();i++){
                if(i==0 || beats[i]!=beats[i-1])
                    addBeatLine(beats[i]);
        }
        if(updateCanvas) canvas->update();
        emit(beatLinesChanged(toArray(beatLines)));
        std::cout<<"beatLines: "<<beatLines.count()<<endl;
        //delete beats;
}




/*!
    \fn DrawSoundWidget::updateBeatLines()
 */
void DrawSoundWidget::updateBeatLines()
{

	QPtrListIterator<BeatLine> it( beatLines );
	BeatLine *beatline;
	while ( (beatline = it.current()) != 0 ) {
		++it;
		beatline->setPen(QColor(0,255,0));
  /*
		beatline->setPoints((beatline->getBeatPos() / getZoomRatio()),
				0,(beatline->getBeatPos()/getZoomRatio()),contentsSize.height());
  */
              beatline->setX(beatline->getBeatPos() / getZoomRatio());
	}

	QPtrListIterator<BeatLine> it2( lockedBeatLines );
	while ( (beatline = it2.current()) != 0 ) {
		++it2;
		beatline->setPen(QColor(0,0,0));
  /*
		beatline->setPoints((beatline->getBeatPos() / getZoomRatio()),
				0,(beatline->getBeatPos()/getZoomRatio()),contentsSize.height());
  */
              beatline->setX(beatline->getBeatPos() / getZoomRatio());
	}

	QPtrListIterator<BeatLine> it3( bpmLines );
	while ( (beatline = it3.current()) != 0 ) {
		++it3;
		beatline->setPen(QColor(255,50,50));
  /*
		beatline->setPoints((beatline->getBeatPos() /getZoomRatio()),
				0,(beatline->getBeatPos()/getZoomRatio()),contentsSize.height());
  */
              beatline->setX(beatline->getBeatPos() / getZoomRatio());
	}
        if(updateCanvas) canvas->update();
}

/*!
    \fn DrawSoundWidget::updateBeatLines()
 */
void DrawSoundWidget::updateNewBeatLines()
{
    mutex.lock();
    for (uint i=0;i<newBeatLines.count();i++){
	newBeatLines.at(i)->setPen(QColor(60,50,100));
 /*
	newBeatLines.at(i)->setPoints((newBeatLines.at(i)->getBeatPos() / getZoomRatio()),30,(newBeatLines.at(i)->getBeatPos()/getZoomRatio()),contentsSize.height()-30);
 */
     newBeatLines.at(i)->setX(newBeatLines.at(i)->getBeatPos() / getZoomRatio());
    }
    if(updateCanvas) canvas->update();
    mutex.unlock();
}



/*!
    \fn DrawSoundWidget::setTreshold(int _treshold)
 */
void DrawSoundWidget::setTreshold(int _treshold, bool viewOnly)
{
    treshold=((double)_treshold)/(double)10.0;
    if(viewOnly){
        setBeatLines(soundManager->analyse(treshold,windowDivider,
                                                                                getFirstVisibleSample(),getLastVisibleSample()));
    }else{
        setBeatLines(soundManager->analyse(treshold,windowDivider));
    }
    analysisFinished();
}

/*!
    \fn DrawSoundWidget::setWindowDivider(int)
 */
void DrawSoundWidget::setWindowDivider(int wd, bool viewOnly)
{
    windowDivider=(int)pow(2,wd);
    soundManager->zapInstantEBuffer();
    if(viewOnly){
        setBeatLines(soundManager->analyse(treshold,windowDivider,
                                                                                getFirstVisibleSample(),getLastVisibleSample()));
    }else{
        setBeatLines(soundManager->analyse(treshold,windowDivider));
    }
    analysisFinished();
}


/*!
    \fn DrawSoundWidget::computeBPM()
 */
double DrawSoundWidget::computeBPM2()
{
    double candidate_bpm=0;
    int count=0;
     float BPM_MIN=60.0;
     float BPM_MAX=200.0;
     long index_min=LONG_MAX;
     long index_max=LONG_MIN;


    QProgressDialog progress("Matching BPM...","Abort",
                                            (BPM_MAX-BPM_MIN),NULL,"progress",TRUE);
    progress.setMinimumDuration(2000);

     //if(FALSE){
     //if(lockedBeatLines.count()>=4 || lockedBeatLines.count()==0){
     if(lockedBeatLines.count()>=4 || beatLines.count()>0){
        QPtrListIterator <BeatLine>it( beatLines );
        QPtrListIterator <BeatLine>it2( lockedBeatLines );
        BeatLine* beatline;
        if(lockedBeatLines.count()>=4){
            it=it2;
        }

        while ( (beatline = it.current()) != 0 ) {
            ++it;
            if (beatline->getBeatPos()<index_min)
                    index_min=beatline->getBeatPos();
            if(beatline->getBeatPos()>index_max)
                    index_max=beatline->getBeatPos();

	}


	long sample_width=index_max-index_min;
	int matching_beat_lines=0;
	int max_matching_beat_lines=0;
	double min_distance=DBL_MAX;

	candidate_bpm=0;
	for (float i=BPM_MIN;i<BPM_MAX;i+=0.010f){
            float beat_distance=(float)(((60.0/(double)i)*soundManager->getRate()));
            float distance_treshold=(float)(beat_distance/64);
            //cout<<beat_distance<<"\n";
            matching_beat_lines=0;
            long current_distance=0;


            for (uint k=0;k<=floor(sample_width/beat_distance);k++){
                long current_bpm_pos=long((index_min+(k*beat_distance)));
                //replacement

                long bl_position=findNearestBeatline(current_bpm_pos);

                long distance=abs(current_bpm_pos-bl_position);
                //std::cout<<"dist: "<<distance<<" dist_tresh: "<<distance_treshold<<endl;
                if(distance<distance_treshold){
                            matching_beat_lines++;
                            current_distance+=distance;
                    }

            }


            if(matching_beat_lines>=max_matching_beat_lines){
                    if(matching_beat_lines==max_matching_beat_lines){
                            if(current_distance<min_distance){
                                    candidate_bpm=i;
                                    min_distance=current_distance;
                            }
                    }else{
                            candidate_bpm=i;
                            max_matching_beat_lines=matching_beat_lines;
                            min_distance=current_distance;
                    }
            }
/*
		if(matching_beat_lines>=max_matching_beat_lines){
			cout<<"bpm: "<<i<<" matching: "<<matching_beat_lines<<" distance: "<<current_distance<<"\n";
		}
*/
            count++;
            if(count%10==0){
                progress.setProgress((i-BPM_MIN));
                progress.setLabelText("Matching BPM...(BPM: "+QString::number(i)+")");
                if(progress.wasCanceled()) break;
                count=0;
            }

	}
     }
     QString bpm_s;
     bpm_s.setNum(candidate_bpm*computedBPMModifier);
     computed_bpm=candidate_bpm;
     emit(bpmChange(tr("BPM: %1").arg(bpm_s)));

     return computed_bpm;
}

double DrawSoundWidget::computeBPM()
{
    double candidate_bpm=0;
    int count=0;
     float BPM_MIN=60.0;
     float BPM_MAX=200.0;
     long index_min=LONG_MAX;
     long index_max=LONG_MIN;


    QProgressDialog progress("Matching BPM...","Abort",
                                            (BPM_MAX-BPM_MIN),NULL,"progress",TRUE);
    progress.setMinimumDuration(2000);

     //if(FALSE){
     //if(lockedBeatLines.count()>=4 || lockedBeatLines.count()==0){
     if(lockedBeatLines.count()>=4 || beatLines.count()>0){
        QPtrListIterator <BeatLine>it( beatLines );
        QPtrListIterator <BeatLine>it2( lockedBeatLines );
        BeatLine* beatline;
        if(lockedBeatLines.count()>=4){
            it=it2;
        }

        while ( (beatline = it.current()) != 0 ) {
            ++it;
            if (beatline->getBeatPos()<index_min)
                    index_min=beatline->getBeatPos();
            if(beatline->getBeatPos()>index_max)
                    index_max=beatline->getBeatPos();

	}


	int matching_beat_lines=0;
	int max_matching_beat_lines=0;
	double min_distance=DBL_MAX;

	candidate_bpm=0;
	for (float i=BPM_MIN;i<BPM_MAX;i+=0.010f){
            float beat_distance=(float)(((60.0/(double)i)*soundManager->getRate()))/4;
            float distance_treshold=(float)(beat_distance/4);
            //cout<<beat_distance<<"\n";
            matching_beat_lines=0;
            long current_distance=0;
            //QPtrListIterator<BeatLine> it2( lockedBeatLines );
            it.toFirst();

            while ( (beatline = it.current()) != 0 ) {
                ++it;
                //replacement

                long bl_position=beatline->getBeatPos();
                double current_k=(bl_position-index_min)/beat_distance;
                float distance=
                    fabs((current_k-((int)current_k%(int)beat_distance))*beat_distance);
                //std::cout<<"dist: "<<distance<<" dist_tresh: "<<distance_treshold<<endl;
                if(distance<distance_treshold){
                    matching_beat_lines++;
                    current_distance+=(long)distance;
                }

                //end replacement
                //replaced
                    /*
                for (uint k=0;k<=floor(sample_width/beat_distance);k++){
                    float current_bpm_pos=(index_min+(k*beat_distance));

                    if(current_bpm_pos-treshold>beatline->getBeatPos()){
                                            break;
                    }

                    float distance=fabs(current_bpm_pos-beatline->getBeatPos());
                    if(distance<distance_treshold){
                            matching_beat_lines++;
                            current_distance+=distance;
                    }
                }
                */
                //end replaced
            }


            if(matching_beat_lines>=max_matching_beat_lines){
                    if(matching_beat_lines==max_matching_beat_lines){
                            if(current_distance<=min_distance){
                                    candidate_bpm=i;
                                    min_distance=current_distance;
                            }
                    }else{
                            candidate_bpm=i;
                            max_matching_beat_lines=matching_beat_lines;
                            min_distance=current_distance;
                    }
            }
/*
		if(matching_beat_lines>=max_matching_beat_lines){
			cout<<"bpm: "<<i<<" matching: "<<matching_beat_lines<<" distance: "<<current_distance<<"\n";
		}
*/
            count++;
            if(count%10==0){
                progress.setProgress(int((i-BPM_MIN)));
                progress.setLabelText("Matching BPM...(BPM: "+QString::number(i)+")");
                if(progress.wasCanceled()) break;
                count=0;
            }

	}
     }
     QString bpm_s;

     computed_bpm=candidate_bpm;
     bpm_s.setNum(getUsedBPM());
     emit(bpmChange(tr("BPM: %1").arg(bpm_s)));

     return computed_bpm;
}

void DrawSoundWidget::computeNewBPMLines(const QString & bpm_s){
	float newBPM=bpm_s.toFloat()*soundManager->getRate()*60;
	float oldBPM=getUsedBPM()*soundManager->getRate()*60;
	new_to_oldBPM_ratio=newBPM/oldBPM;
        /*
	for (uint i=0;i<newBeatLines.count();i++){
		delete newBeatLines.at(i);
    		newBeatLines.remove(i);
    	}
	for (uint i=0;i<lockedBeatLines.count();i++){
		long newPosition=(long)((lockedBeatLines.at(i)->getBeatPos()*oldBPM)/newBPM);
		BeatLine* beatline=new BeatLine(canvas,newPosition);
                beatline->setSampleValueView(sampleValueView);
		beatline->show();
		newBeatLines.append(beatline);
	}
	updateNewBeatLines();
        */
}






/*!
    \fn DrawSoundWidget::unlockBeatLines()
 */
void DrawSoundWidget::unlockBeatLines()
{
	QPtrListIterator<BeatLine> it( lockedBeatLines );
	BeatLine *beatline=0;
	while ( (beatline = it.current()) != 0 ) {
		++it;
		beatline->unlock();
    		beatLines.append(beatline);
		lockedBeatLines.remove(beatline);
    	}
    	updateBeatLines();
        updateLockedBeatRects();
        emit(beatLinesChanged(toArray(beatLines)));
        emit(lockedBeatLinesChanged(toArray(lockedBeatLines)));
}

/*!
    \fn DrawSoundWidget::unlockBeatLines()
 */
void DrawSoundWidget::lockBeatLines()
{
    QPtrListIterator<BeatLine> it( beatLines );
    BeatLine *beatline=0;
    while ( (beatline = it.current()) != 0 ) {
        ++it;
        beatline->lock();
        lockedBeatLines.append(beatline);
        beatLines.remove(beatline);
    }
    updateBeatLines();
    updateLockedBeatRects();
    emit(beatLinesChanged(toArray(beatLines)));
    emit(lockedBeatLinesChanged(toArray(lockedBeatLines)));
}

void DrawSoundWidget::reinitCanvas(){
    //delete Lines
    unlockBeatLines();
    QPtrListIterator<BeatLine> it( beatLines );
    BeatLine *beatline=0;
    while ( (beatline = it.current()) != 0 ) {
            ++it;
            delete beatline;
            beatLines.remove(beatline);
    }
    QPtrListIterator<BeatLine> it2( bpmLines );
    while ( (beatline = it2.current()) != 0 ) {
            ++it2;
            delete beatline;
            beatLines.remove(beatline);
    }

    QPtrListIterator<BeatLine> it3( newBeatLines);
    while ( (beatline = it3.current()) != 0 ) {
            ++it3;
            delete beatline;
            newBeatLines.remove(beatline);
    }

    //deleteSelections
    removeSelectionRectangles();

    setBeatLines(soundManager->analyse(treshold,windowDivider));
    setPositionPointer((int)((double)playPosition/getZoomRatio()));
    updateSelectionRectangles();
    updateVerticalSelectionRectangles();
    updateLoopMarkers();
    analysisFinished();
}

/*!
    \fn DrawSoundWidget::updateSelectionRectangles()
 */
void DrawSoundWidget::updateSelectionRectangles()
{
    if(selection->isVisible()){
        selection->setX(selection->getStartSamplePosition()/getZoomRatio());
        selection->setY(20);
            int newWidth=
                    selection->getEndSamplePosition()/getZoomRatio()-selection->x();
            if(newWidth>0)
                selection->setSize(newWidth,canvas->height()-20);
        if(updateCanvas) canvas->update();
    }
}

/*!
    \fn DrawSoundWidget::updateVerticalSelectionRectangles()
 */
void DrawSoundWidget::updateVerticalSelectionRectangles()
{
    for (uint i=0;i<verticalSelections.count();i++){
	verticalSelections.at(i)->setX(contentsX());
         int y=(visibleHeight()*(512-verticalSelections.at(i)->getStartBandPos()))/512;
         cout<<"Y: "<<y<<"\n";
	verticalSelections.at(i)->setY(y);

	int newHeight=-(visibleHeight()*(verticalSelections.at(i)->getEndBandPos()-verticalSelections.at(i)->getStartBandPos()))/512;

	verticalSelections.at(i)->setSize(this->width(),newHeight);

 cout<<"start: "<<verticalSelections.at(i)->getStartBandPos()<<" end: "<<verticalSelections.at(i)->getEndBandPos()<<" height: "<<newHeight<<"\n";
    }
    if(updateCanvas) canvas->update();
}

void DrawSoundWidget::updateLoopMarkers()
{
        if(loopMarkerL->getSamplePosition()<0)
            loopMarkerL->setSamplePosition(0);
        if(loopMarkerR->getSamplePosition()>soundManager->getFrames())
            loopMarkerR->setSamplePosition(soundManager->getFrames());
        loopMarkerL->setX(loopMarkerL->getSamplePosition()/getZoomRatio());
        loopMarkerR->setX(loopMarkerR->getSamplePosition()/getZoomRatio());
}


void DrawSoundWidget::resample(){
	list<long> sortedPos;
        sortedPos.push_front(soundManager->getFrames()); //end of sample
	for (uint i=0;i<lockedBeatLines.count();i++){
			sortedPos.push_front(lockedBeatLines.at(i)->getBeatPos());
	}
	sortedPos.sort();
	soundManager->resample(sortedPos,new_to_oldBPM_ratio);
         //zoomAll();  //problem!!
        reinitCanvas();
}





/*!
    \fn DrawSoundWidget::zoomToSel()
 */
long DrawSoundWidget::zoomToSel()
{
	if(selection->isVisible()){
		long start=selection->getStartSamplePosition();
		long end=selection->getEndSamplePosition();
		long new_zr= zoomToSamplePos(start,end);
		return new_zr;
	}
	return getZoomRatio();
}


/*!
    \fn DrawSoundWidget::zoomAll()
 */
long DrawSoundWidget::zoomAll()
{
    cout<<"in "<<name()<<": zoomAll("<<")\n";
    long new_zr= zoomToSamplePos(0,soundManager->getFrames());
	return new_zr;

}





/*!
    \fn DrawSoundWidget::setBPMLines()
 */
void DrawSoundWidget::setBPMLines(bool on)
{
    removeBPMLines();
    if(on){
        if(computed_bpm>0){
            long index_min=LONG_MAX;
            for (uint i=0;i<lockedBeatLines.count();i++){
                    if (lockedBeatLines.at(i)->getBeatPos()<index_min)
                            index_min=lockedBeatLines.at(i)->getBeatPos();
            }
            int drawn_beat_distance=(int)floor((60.0/(double)computed_bpm)*soundManager->getRate());
            for (uint i=index_min;
            i<=soundManager->getFrames()-drawn_beat_distance;i+=drawn_beat_distance){
                    BeatLine* beatline=new BeatLine(canvas,i);
                    beatline->setSampleValueView(sampleValueView);
                    beatline->setPen(QColor(255,100,100));
                    beatline->setX((int)((double)i/getZoomRatio()));
                    /*
                    beatline->setPoints((int)((double)i/getZoomRatio()),0,
                                                    (int)((double)i/getZoomRatio()),this->visibleHeight());
                    */
                    beatline->setBpmLine();
                    beatline->show();
                    bpmLines.append(beatline);
            }
            for (int i=index_min-drawn_beat_distance;
            i>=drawn_beat_distance;i-=drawn_beat_distance){
                    BeatLine* beatline=new BeatLine(canvas,i);
                    beatline->setSampleValueView(sampleValueView);
                    beatline->setPen(QColor(255,100,100));
                    beatline->setX((int)((double)i/getZoomRatio()));
                    /*
                    beatline->setPoints((int)((double)i/getZoomRatio()),0,
                                                    (int)((double)i/getZoomRatio()),contentsSize.height());
                    */
                    beatline->setBpmLine();
                    beatline->show();
                    bpmLines.append(beatline);
            }
            if(updateCanvas) canvas->update();
        }
    }
}


/*!
    \fn DrawSoundWidget::removeBPMLines()
 */
void DrawSoundWidget::removeBPMLines()
{
	QPtrListIterator<BeatLine> it( bpmLines );
	BeatLine *beatline;
	while ( (beatline = it.current()) != 0 ) {
		++it;
		beatline->hide();
		bpmLines.remove(beatline);
		delete beatline;
	}
	if(updateCanvas) canvas->update();
}

void DrawSoundWidget::zoomChanged(){
    updateCanvas=false;
    setPositionPointer(playPosition);
    updateBeatLines();
    updateLockedBeatRects();
    updateSelectionRectangles();
    updateVerticalSelectionRectangles();
    updateLoopMarkers();
    updateCanvas=true;
    canvas->update();
    emit(visibleAreaChanged(getFirstVisibleSample(),getLastVisibleSample()));
    emit(zoomChangedS(getZoomRatio()));
}



/*!
    \fn DrawSoundWidget::getNearestLinePos(QPoint)
 */
void DrawSoundWidget::getNearestLinePos(QPoint pos,long& sample_pos,int& x)
{
    QCanvasItemList colisions=canvas->collisions(pos);
    if(!colisions.isEmpty()){
        QCanvasItemList::iterator it;
        for ( it = colisions.begin(); it != colisions.end(); ++it ){
                if((*it)->rtti()==RTTI_BEATLINE){
                    BeatLine* temp=(BeatLine*)(*it);
                    x=temp->x();
                    sample_pos=temp->getBeatPos();
                    //cout<<"x: "<<x<<" sample_pos: "<<sample_pos<<endl;
                }
        }
   }
}

void DrawSoundWidget::contentsMoved(int x,int y){
    canvas->setPixmapXOrigin(x);
    long start_sample=x*getZoomRatio();
    long end_sample=(x+width())*getZoomRatio();

    /*
    cout<<"in contentsMoved("<<x<<","<<y<<"): start_sample="<<start_sample<<" end sample="<<end_sample<<"\n";

    assert(x*getZoomRatio()>=0);
    //assert((x+visibleWidth())*getZoomRatio()<=soundManager->getFrames());
    */

    start_sample=checkSamplePosition(start_sample);
    end_sample=checkSamplePosition(end_sample);

    assert(end_sample>start_sample);
    forceRepaint(start_sample,end_sample);
    emit(visibleAreaChanged(start_sample,end_sample));
    blockSignals(TRUE);
    emit(contentsMoving(x,y));
    blockSignals(FALSE);
    //updateVerticalSelectionRectangles();
}


/*!
    \fn DrawSoundWidget::getSelectionStartSample()
 */
long DrawSoundWidget::getSelectionStartSample()
{
    if(selection->isVisible()){
        long start_sample=selection->getStartSamplePosition();
        return start_sample<0?0:start_sample;
    }else return -1;
}


/*!
    \fn DrawSoundWidget::getSelectionEndSample()
 */
long DrawSoundWidget::getSelectionEndSample()
{
    if(selection->isVisible()){
        long end_sample=selection->getEndSamplePosition();
        return end_sample>soundManager->getFrames()?soundManager->getFrames():end_sample;
    }else return -1;
}



/*!
    \fn DrawSoundWidget::getLockedBeats()
 */
void DrawSoundWidget::getBeats(long tempBeats[])
{

    QPtrListIterator<BeatLine> it( beatLines );
    BeatLine *beatline;
    int count=0;
    while ( (beatline = it.current()) != 0 ) {
        ++it;
        tempBeats[count]=beatline->getBeatPos();
	//cout<<"unlocked: "<<tempBeats[count]<<endl;
	count++;
    }

    QPtrListIterator<BeatLine> it2( lockedBeatLines );
    while ( (beatline = it2.current()) != 0 ) {
        ++it2;
        tempBeats[count]=beatline->getBeatPos();
	//cout<<"locked: "<<tempBeats[count]<<endl;
        count++;
    }

}


/*!
    \fn DrawSoundWidget::getNbLockedBeats()
 */
int DrawSoundWidget::getNbLockedBeats()
{
    return lockedBeatLines.count();
}

int DrawSoundWidget::getNbBeats()
{
    return beatLines.count()+lockedBeatLines.count();
}


/*!
    \fn DrawSoundWidget::analysisFinished()
 */
void DrawSoundWidget::analysisFinished()
{
    computeBPM();
    //canvas->update();
}


/*!
    \fn DrawSoundWidget::event(QEvent*)
 */
void DrawSoundWidget::customEvent(QCustomEvent* ev)
{
    if(ev->type() == 346798){
        if(!((PlayPositionChanged*)ev)->getPlaying()){
            getPositionPointerCI()->setState(PlayLine::STATE_STOPPED);
        }else{
            getPositionPointerCI()->setState(PlayLine::STATE_PLAYING);
        }
        this->setPositionPointer(((PlayPositionChanged*)ev)->getPosition());
    }
}


/*!
    \fn DrawSoundWidget::getComputedBPM()
 */
double DrawSoundWidget::getComputedBPM()
{
    return computed_bpm;
}

/*!
    \fn DrawSoundWidget::getUsedBPM()
 */
double DrawSoundWidget::getUsedBPM()
{
    return computed_bpm*computedBPMModifier;
}


/*!
    \fn DrawSoundWidget::hasLoopSet()
 */
bool DrawSoundWidget::hasLoopSet()
{
    return !(*loopMarkerL==loopMarkerR);

}


/*!
    \fn DrawSoundWidget::getLeftLoopMarkerSample()
 */
long DrawSoundWidget::getLeftLoopMarkerSample()
{
    return loopMarkerL->getSamplePosition();
}


/*!
    \fn DrawSoundWidget::getRightLoopMarkerSample()
 */
long DrawSoundWidget::getRightLoopMarkerSample()
{
    return loopMarkerR->getSamplePosition();
}


/*!
    \fn DrawSoundWidget::swapMarkers(LoopMarker*,LoopMarker*)
 */
void DrawSoundWidget::swapMarkers()
{
    if(*loopMarkerL>loopMarkerR){
        std::swap(loopMarkerL, loopMarkerR);
        loopMarkerL->setSide(LoopMarker::LEFT_MARKER);
        loopMarkerR->setSide(LoopMarker::RIGHT_MARKER);
        measureMarker->swapMarkers();
        canvas->setAllChanged();
    }
}


/*!
    \fn DrawSoundWidget::findLeftBeatline(long)
 */
long DrawSoundWidget::findLeftBeatline(long sample_pos)
{
    int size=getNbBeats();
    long* temp=new long[size];
    getBeats(temp);
    std::sort(&temp[0],&temp[size-1]);
    long leftmost=0;
    for (int i=0;i<size;i++){
        if(temp[i]<=sample_pos){
            if(temp[i]>leftmost) leftmost=temp[i];
        }
    }
    zaparr(temp);
    return leftmost;
}


/*!
    \fn DrawSoundWidget::findRightBeatline(long)
 */
long DrawSoundWidget::findRightBeatline(long sample_pos)
{
    int size=getNbBeats();
    long* temp=new long[size];
    getBeats(temp);
    std::sort(&temp[0],&temp[size-1]);
    long rightmost=soundManager->getFrames();
    for (int i=size-1;i>=0;i--){
        if(temp[i]>=sample_pos){
            if(temp[i]<rightmost) rightmost=temp[i];
        }
    }
    zaparr(temp);
    return rightmost;
}

long DrawSoundWidget::findNearestBeatline(long sample_pos){
    long left=findLeftBeatline(sample_pos);
    long right=findRightBeatline(sample_pos);
    if((sample_pos-left)<(right-sample_pos)) return left;
    else return right;
}


/*!
    \fn DrawSoundWidget::setLoopMarkersOnMeasure(long)
 */
void DrawSoundWidget::setLoopMarkersOnMeasure(int fst_beatline)
{
    int size=getNbBeats();
    if(size>=2){
        long* temp=new long[size];
        getBeats(temp);
        std::sort(&temp[0],&temp[size-1]);
        loopMarkerL->setSamplePosition(temp[fst_beatline]);
        float mesure_distance=4.0*getBeatDistance();
        loopMarkerR->setSamplePosition(findNearestBeatline(long(temp[fst_beatline]+mesure_distance)));
        zaparr(temp);
    }else{
        loopMarkerL->setSamplePosition(0);
        loopMarkerR->setSamplePosition(soundManager->getFrames());
    }
    updateLoopMarkers();
}


/*!
    \fn DrawSoundWidget::getBeatDistance()
 */
float DrawSoundWidget::getBeatDistance()
{
    return (float)(((60.0/(double)getUsedBPM())*soundManager->getRate()));
}

void DrawSoundWidget::cropped(long start,long end){
    //recompute loop markers
    if((loopMarkerL->getSamplePosition()<start && loopMarkerR->getSamplePosition()<start)||
        (loopMarkerL->getSamplePosition()>end && loopMarkerR->getSamplePosition()>end)){
        loopMarkerL->setSamplePosition(0);
        loopMarkerR->setSamplePosition(soundManager->getFrames());
    }else{
        if (loopMarkerL->getSamplePosition()<start)
            loopMarkerL->setSamplePosition(0);
        else
            loopMarkerL->setSamplePosition(loopMarkerL->getSamplePosition()-start);

        if (loopMarkerR->getSamplePosition()>end)
            loopMarkerR->setSamplePosition(soundManager->getFrames());
        else
            loopMarkerR->setSamplePosition(loopMarkerR->getSamplePosition()-start);
    }
    updateLoopMarkers();

    //recompute selections
        if((selection->getStartSamplePosition()<start && selection->getEndSamplePosition()<start)||
             (selection->getStartSamplePosition()<start && selection->getEndSamplePosition()<start)){
            selection->setStartSamplePosition(0);
            selection->setEndSamplePosition(soundManager->getFrames());
        }else{
            if(selection->getStartSamplePosition()<start)
                selection->setStartSamplePosition(0);
            else
                selection->setStartSamplePosition(selection->getStartSamplePosition()-start);

            if(selection->getEndSamplePosition()>end)
                selection->setEndSamplePosition(soundManager->getFrames());
            else
                selection->setEndSamplePosition(selection->getEndSamplePosition()-start);
        }
    updateSelectionRectangles();
    updateVerticalSelectionRectangles();

   //remove cropped beatlines
        BeatLine *beatline;
        QPtrListIterator<BeatLine> it( beatLines );
        
        while ( (beatline = it.current()) != 0 ) {
                ++it;
                if(beatline->getBeatPos()<start || beatline->getBeatPos()>end){
                    beatLines.remove(beatline);
                    delete beatline;
                }
                else{
                    beatline->setSamplePos(beatline->getBeatPos()-start);
                }
        }
        emit(beatLinesChanged(toArray(beatLines)));
        QPtrListIterator<BeatLine> it2( lockedBeatLines );
        while ( (beatline = it2.current()) != 0 ) {
                ++it2;
                if(beatline->getBeatPos()<start || beatline->getBeatPos()>=end){
                    lockedBeatLines.remove(beatline);
                    delete beatline;
                }else{
                    beatline->setSamplePos(beatline->getBeatPos()-start);
                }
        }
        canvas->update();
        emit(lockedBeatLinesChanged(toArray(lockedBeatLines)));
    zoomAll();
}


/*!
    \fn DrawSoundWidget::showBeatLines(bool)
 */
void DrawSoundWidget::showBeatLines(bool tf)
{
    QCanvasItemList items=canvas->allItems();
    QCanvasItemList::iterator it;
    for ( it = items.begin(); it != items.end(); ++it ){
        if ((*it)->rtti()==RTTI_BEATLINE){
            if(tf) (*it)->show();
            else (*it)->hide();
        }
    }
    if(updateCanvas) canvas->update();
    showBeatLinesVal=tf;
}


/*!
    \fn DrawSoundWidget::setComputedBPMModifier(double)
 */
void DrawSoundWidget::setComputedBPMModifier(double m)
{
    computedBPMModifier=m;
    QString bpm_s;
    bpm_s.setNum(getUsedBPM());
     emit(bpmChange(tr("BPM: %1").arg(bpm_s)));
}



/*!
    \fn DrawSoundWidget::handleMouseMoveSelectionRectangles(QMouseEvent* me)
 */
void DrawSoundWidget::handleMouseMoveSelectionRectangles(QMouseEvent* mouseEvent)
{
    if(selection->isVisible()){
        int pos_x=mouseEvent->pos().x();
        long sample_pos=pos_x*getZoomRatio();
        if(selection->getMoving()){
            //when moving, magnet lines based on left and right side of the selection
            long moving_sample_pos=0;
            int moving_pos_x=0;
            if(mouseEvent->pos().x()-savedRelativeSamplePos/getZoomRatio()<selection->x()){
                //moving to the left
                QPoint left(selection->x(),mouseEvent->pos().y());
                getNearestLinePos(left,moving_sample_pos,moving_pos_x);
            }else{
                //moving to the right
                QPoint right(selection->x()+selection->width(),mouseEvent->pos().y());
                getNearestLinePos(right,moving_sample_pos,moving_pos_x);
            }
            if(fabs((mouseEvent->pos().x()-savedRelativeSamplePos/getZoomRatio())-moving_pos_x)<20){
                /** \todo finish mangnet lines when moving */
                //sample_pos=moving_sample_pos;
                //pos_x=moving_pos_x;
            }
        }else{
            computePosFromMouse(mouseEvent,pos_x,sample_pos);
        }
        if(selection->getResizing()){
            //resizing selection to the right
            setCursor(QCursor(Qt::SizeHorCursor));
            if(sample_pos<selection->getStartSamplePosition()){
                selection->setResizing(FALSE);
                selection->setLeftSideResizing(TRUE);
            }
            selection->setEndSamplePosition(sample_pos);
            updateSelectionRectangles();
        }else if(selection->getLeftSideResizing()){
            //resizing selection to the left
            setCursor(QCursor(Qt::SizeHorCursor));
            if(sample_pos>selection->getEndSamplePosition()){
                selection->setResizing(TRUE);
                selection->setLeftSideResizing(FALSE);
            }
            selection->setStartSamplePosition(sample_pos);
            updateSelectionRectangles();
        }else if(selection->getMoving()){
            //moving view
            long relativeSamplePosition=sample_pos-savedRelativeSamplePos;
            long sample_width=selection->getEndSamplePosition()-selection->getStartSamplePosition();
            setCursor(QCursor(Qt::SizeAllCursor ));
            long start_sample_pos=relativeSamplePosition;
            long end_sample_pos=relativeSamplePosition+sample_width;
            if(start_sample_pos>=0 && end_sample_pos<=soundManager->getFrames()){
                selection->setStartSamplePosition(checkSamplePosition(start_sample_pos));
                selection->setEndSamplePosition(checkSamplePosition(end_sample_pos));
            }
            updateSelectionRectangles();
        }else if(selection->getCenterRect()->contains(mouseEvent->pos())){
                //moving view
            setCursor(QCursor(Qt::SizeAllCursor ));
        }else if(selection->getLeftRect()->contains(mouseEvent->pos()) ||
                    selection->getRightRect()->contains(mouseEvent->pos())){
                            //adjusting selection
            setCursor(QCursor(Qt::SizeHorCursor));
        }else{
            setCursor(QCursor(Qt::ArrowCursor));
        }
    }
}


/*!
    \fn DrawSoundWidget::computePosFromMouse(QMouseEvent* me, int& pos_x, long& sample_pos)
 */
void DrawSoundWidget::computePosFromMouse(QMouseEvent* mouseEvent, int& pos_x, long& sample_pos)
{

    QPoint pos=mouseEvent->pos();
    pos_x=pos.x();
    pos_x=pos_x<contentsX()?
                contentsX():pos_x>contentsX()+width()?
                    contentsX()+width():pos_x;
    sample_pos=pos_x*getZoomRatio();
    sample_pos=sample_pos>soundManager->getFrames()?soundManager->getFrames():sample_pos;
    sample_pos=sample_pos<0?0:sample_pos;
    // magnet selection line
    int temp_pos_x=pos_x;
    long temp_sample_pos=sample_pos;
    this->getNearestLinePos(pos,temp_sample_pos,temp_pos_x);
    if(pos_x!=temp_pos_x && fabs(pos_x-temp_pos_x)<3){
        sample_pos=temp_sample_pos;
        pos_x=temp_pos_x;
    }
}


/*!
    \fn DrawSoundWidget::handleMouseMoveVerticalSelectionRectangle(QMouseEvent* mouseEvent)
 */
void DrawSoundWidget::handleMouseMoveVerticalSelectionRectangles(QMouseEvent* mouseEvent)
{
    if(!verticalSelections.isEmpty()){
        if(verticalSelections.first()->getResizing()){
            //resizing vertical selection to the top
            setCursor(QCursor(Qt::SizeVerCursor));
            int endBandPos=((visibleHeight()-mouseEvent->pos().y())*512)/canvas->height();
            verticalSelections.first()->setEndBandPos(endBandPos);
            updateVerticalSelectionRectangles();
        }else if(!verticalSelections.isEmpty() &&
                                 mouseEvent->pos().y()>verticalSelections.first()->y()+10 &&
                                 mouseEvent->pos().y()<verticalSelections.first()->y()+abs(verticalSelections.first()->height())-10){
             //if(mouseEvent->state() & ShiftButton)  setCursor(QCursor(Qt::SizeAllCursor ));
        }else{
            setCursor(QCursor(Qt::ArrowCursor));
        }
    }
}


/*!
    \fn DrawSoundWidget::handleMouseMoveLoopMarkers(MouseEvent* mouseEvent)
 */
void DrawSoundWidget::handleMouseMoveLoopMarkers(QMouseEvent* mouseEvent)
{
    if(loopMarkerL->getMoving() || loopMarkerR->getMoving()){
        long sample_pos=0;
        int pos_x=0;
        computePosFromMouse(mouseEvent,pos_x,sample_pos);
        //moving loop markers
        setCursor(QCursor(Qt::SizeHorCursor));
        LoopMarker* choosenMarker=0;
        if(loopMarkerL->getMoving()) choosenMarker=loopMarkerL;
        else choosenMarker=loopMarkerR;
        choosenMarker->setSamplePosition(sample_pos);
        choosenMarker->setX(pos_x);
        if (*loopMarkerL>loopMarkerR) swapMarkers();
        updateLoopMarkers();
        if (!measureMarker->isVisible()) measureMarker->show();
        canvas->update();
    }
}


/*!
    \fn DrawSoundWidget::getMovableBeatLine(QPoint pos)
 */
BeatLine* DrawSoundWidget::getMovableBeatLine(QPoint pos)
{
    QPtrListIterator<BeatLine> it( beatLines );
    BeatLine *beatline;
    while ( (beatline = it.current()) != 0 ) {
            ++it;
        if(beatline->getHandle()->contains(pos)) return beatline;
    }

    QPtrListIterator<BeatLine> it2( lockedBeatLines );
    while ( (beatline = it2.current()) != 0 ) {
            ++it2;
            if(beatline->getHandle()->contains(pos)) return beatline;
    }
    return 0;
}

/*!
        \fn DrawSoundWidget::getMovableBeatRect(QPoint pos)
 */
LockedBeatRect* DrawSoundWidget::getMovableBeatRect(QPoint pos)
{
    QPtrListIterator<LockedBeatRect> it( lockedBeatRects );
    LockedBeatRect *beatrect;
    while ( (beatrect = it.current()) != 0 ) {
        ++it;
        if(beatrect->getHandle()->contains(pos)) return beatrect;
    }
    return 0;
}

/*!
        \fn DrawSoundWidget::getMovingBeatRect()
 */
LockedBeatRect* DrawSoundWidget::getMovingBeatRect()
{
    QPtrListIterator<LockedBeatRect> it( lockedBeatRects );
    LockedBeatRect *beatrect;
    while ( (beatrect = it.current()) != 0 ) {
        ++it;
        if(beatrect->isSelected()) return beatrect;
    }
    return 0;
}

/*!
    \fn DrawSoundWidget::getMovableBeatLine(QPoint pos)
 */
BeatLine* DrawSoundWidget::getLockableBeatLine(QPoint pos)
{
    QPtrListIterator<BeatLine> it( beatLines );
    BeatLine *beatline;
    while ( (beatline = it.current()) != 0 ) {
            ++it;
        if(beatline->getLockUnlockHandle()->contains(pos)) return beatline;
    }

    QPtrListIterator<BeatLine> it2( lockedBeatLines );
    while ( (beatline = it2.current()) != 0 ) {
            ++it2;
            if(beatline->getLockUnlockHandle()->contains(pos)) return beatline;
    }
    return 0;
}

/*!
    \fn DrawSoundWidget::getMovableBeatLine(QPoint pos)
 */
BeatLine* DrawSoundWidget::getRemovableBeatLine(QPoint pos)
{
    QPtrListIterator<BeatLine> it( beatLines );
    BeatLine *beatline;
    while ( (beatline = it.current()) != 0 ) {
            ++it;
        if(beatline->getRemoveHandle()->contains(pos)) return beatline;
    }
    return 0;
}


/*!
    \fn DrawSoundWidget::getMovingBeatLine()
 */
BeatLine* DrawSoundWidget::getMovingBeatLine()
{
    QPtrListIterator<BeatLine> it( beatLines );
    BeatLine *beatline;
    while ( (beatline = it.current()) != 0 ) {
            ++it;
        if(beatline->isMoving()) return beatline;
    }

    QPtrListIterator<BeatLine> it2( lockedBeatLines );
    while ( (beatline = it2.current()) != 0 ) {
            ++it2;
            if(beatline->isMoving()) return beatline;
    }
    return 0;
}


/*!
    \fn DrawSoundWidget::handleMousMoveBeatLine(MouseEvent* mouseEvent)
 */
void DrawSoundWidget::handleMouseMoveBeatLine(QMouseEvent* mouseEvent)
{
    if(BeatLine* beatline=getMovingBeatLine()){
        long sample_pos=0;
        int pos_x=0;
        computePosFromMouse(mouseEvent,pos_x,sample_pos);
        beatline->setX(pos_x);
        beatline->setSamplePos(sample_pos);
        canvas->update();
    }else if(getMovableBeatLine(mouseEvent->pos())){
        setCursor(QCursor(Qt::SizeHorCursor));
    }else{
        setCursor(QCursor(Qt::Qt::ArrowCursor ));
    }
}

/*!
    \fn DrawSoundWidget::handleMousMoveBeatRect(MouseEvent* mouseEvent)
 */
void DrawSoundWidget::handleMouseMoveBeatRect(QMouseEvent* mouseEvent)
{
    if(LockedBeatRect* beatrect=getMovingBeatRect()){
        QString tempfilename=QString::number(beatrect->getNb()).rightJustify(8,'0').append(".")
                                                .append(soundManager->getFileExtension());

        QString orig=tempfilename;
        orig.prepend("orig-").prepend(soundManager->getTempDir()+"/");

        QString final=tempfilename;
        final.prepend(soundManager->getTempDir()+"/");

        QString ladspa=tempfilename;
        ladspa.prepend("ladspa-").prepend(soundManager->getTempDir()+"/");


        QStrList filelist;

        soundManager->saveChunkToAs(   final,
                                       beatrect->getStartSample(),
                                       beatrect->getEndSample(),-1,0,SoundHolder::FOR_OUTPUT);
        filelist.append(final);

        /*
        soundManager->saveChunkToAs(   orig,
                                       beatrect->getStartSample(),
                                       beatrect->getEndSample(),-1,0,SoundHolder::ORIGINAL_WAVE);
        filelist.append(orig);

        if(soundManager->getHasLADSPA()){
            soundManager->saveChunkToAs(   ladspa,
                                           beatrect->getStartSample(),
                                           beatrect->getEndSample(),-1,0,SoundHolder::FOR_OUTPUT);
            filelist.append(ladspa);
        }
        */

        WaveDrag* waveDrag=new WaveDrag(filelist,this);

        QPixmap pixmap=QPixmap::grabWidget(this);
        QPixmap pixmap2;
        pixmap2.resize((beatrect->getEndSample()-beatrect->getStartSample())/getZoomRatio(),
                                        pixmap.height()-40);
        copyBlt(&pixmap2,0,0,&pixmap,beatrect->x()-contentsX(),20,pixmap2.width(),pixmap2.height());

        QWMatrix m;
        m.scale(.5,.25);
        QPixmap scaledPixmap = pixmap2.xForm(m);
        waveDrag->setPixmap(scaledPixmap);
        waveDrag->dragMove();
        beatrect->setSelected(FALSE);
        canvas->update();
    }
}

void DrawSoundWidget::contentsDragEnterEvent(QDragEnterEvent* event)
{
    cout<<"contentsDragEnterEvent\n";
    if(lockedBeatLines.count()>0 && QUriDrag::canDecode(event)){
        QStringList list;
        QUriDrag::decodeLocalFiles(event,list);
        cout<<"Dragged file: "<<list.front()<<endl;
        event->accept(soundManager->canOpen(list.front()));
    }
}

void DrawSoundWidget::contentsDragMoveEvent(QDragMoveEvent* event)
{
    if(event->isActionAccepted()){
        QPoint pos=event->pos();
        QCanvasItemList colisions=canvas->collisions(pos);
        cout<<"drag pos: "<<pos.x()<<endl;
    }
}

void DrawSoundWidget::contentsDropEvent(QDropEvent* event)
{
        int insertpos=event->pos().x();
        QStringList list;
        QUriDrag::decodeLocalFiles(event,list);
        soundManager->insertFileAt(list.front(),0);
        cout<<"wavefile dropped\n";
}





/*!
    \fn DrawSoundWidget::removeSelectionRectangles()
 */
void DrawSoundWidget::removeSelectionRectangles()
{
    cout<<"hiding selection rectangle\n";
    selection->hide();
    selection->setSize(0,0);
    selection->setX(0);
    selection->setStartSamplePosition(0);
    selection->setEndSamplePosition(0);
    if(updateCanvas) canvas->update();
}


/*!
    \fn DrawSoundWidget::checkAndScroll(int x)
 */
void DrawSoundWidget::checkAndScroll(QMouseEvent* event)
{
    // start autoscrolling if necessary
    storedMouse=event;
    scrollPos=storedMouse->pos();
    if(((abs(scrollPos.x()-(contentsX()+width()))<20) && (contentsX()+width()<contentsWidth())) ||
        ((abs(scrollPos.x()-contentsX())<20) &&(contentsX()>20))){
        if(!scrollTimer->isActive()) scrollTimer->start(1);
    }else{
        scrollTimer->stop();
    }
}


/*!
    \fn DrawSoundWidget::scroll()
 */
void DrawSoundWidget::scroll()
{
    bool scrolled=FALSE;
    int rightScrollArea=scrollPos.x()-(contentsX()+width());
    int leftScrollArea=scrollPos.x()-contentsX();
    if(abs(rightScrollArea)<20){
        int scrollAmount=abs(rightScrollArea)<10?8:4;
        scrollBy(scrollAmount,0);
        scrollPos.rx()+=scrollAmount;
        scrolled=TRUE;
    }else if(abs(leftScrollArea)<20){
        int scrollAmount=abs(leftScrollArea)<10?8:4;
        scrollBy(-scrollAmount,0);
        scrollPos.rx()-=scrollAmount;
        scrolled=TRUE;
    }
    if(scrolled){
        handleMouseMoveBeatLine(storedMouse);
        handleMouseMoveSelectionRectangles(storedMouse);
        handleMouseMoveVerticalSelectionRectangles(storedMouse);
        handleMouseMoveLoopMarkers(storedMouse);
    }
}


/*!
    \fn DrawSoundWidget::toArray(QPtrList<BeatLine> beatlines)
 */
QValueList<long> DrawSoundWidget::toArray(QPtrList<BeatLine> beatlines)
{
    QValueList<long> returnArray;
    QPtrListIterator<BeatLine> it( beatlines );
    BeatLine *beatline;
    while ( (beatline = it.current()) != 0 ) {
        ++it;
        returnArray.append(beatline->getBeatPos());
    }
    qHeapSort(returnArray);
    return returnArray;
}


/*!
    \fn DrawSoundWidget::findNextLockedBeatLine(BeatLine bl)
 */
BeatLine* DrawSoundWidget::findNextLockedBeatLine(BeatLine* bl)
{
    lockedBeatLines.sort();
    QPtrListIterator<BeatLine> it( lockedBeatLines );
    BeatLine *beatline;
    while ( (beatline = it.current()) != 0 ) {
        ++it;
        if (beatline->getBeatPos()>bl->getBeatPos() && beatline->locked()) return beatline;
    }
    return 0;
}


/*!
    \fn DrawSoundWidget::getLockedBeatList()
 */
QValueList<long> DrawSoundWidget::getLockedBeatList()
{
    return toArray(lockedBeatLines);
}


/*!
    \fn DrawSoundWidget::updateLockedBeatRects()
 */
void DrawSoundWidget::updateLockedBeatRects()
{

    lockedBeatLines.sort();
    lockedBeatRects.clear();
    QPtrListIterator<BeatLine> it( lockedBeatLines );
    BeatLine *beatline,*beatline2;
    int color=0;
    int count=0;
    while ( (beatline = it.current()) != 0 ) {
        ++it;
        beatline2=it.current();
        if(beatline2!=0){
            LockedBeatRect* lr=new LockedBeatRect(canvas,
                                                    beatline,beatline2);
            lr->setNb(count);
            lr->setColor(color);
            lr->show();
            lockedBeatRects.append(lr);
            color=(color+1)%2;
            count++;
        }
    }
    if(updateCanvas) canvas->update();


}


/*!
    \fn DrawSoundWidget::setLockedBeatLines(QValueList <long> lbl)
 */
void DrawSoundWidget::setLockedBeatLines(QValueList <long> lbl)
{
    for (int i=0;i<lbl.count();i++){
        addLockedBeatLine(lbl[i]);
    }
    updateCanvas=FALSE;
    updateBeatLines();
    updateLockedBeatRects();
    updateCanvas=TRUE;
    canvas->update();
    emit(lockedBeatLinesChanged(toArray(lockedBeatLines)));
}


/*!
    \fn DrawSoundWidget::getLeftLoopMarker()
 */
LoopMarker* DrawSoundWidget::getLeftLoopMarker()
{
    return loopMarkerL;
}


/*!
    \fn DrawSoundWidget::getRightLoopMarker()
 */
LoopMarker* DrawSoundWidget::getRightLoopMarker()
{
    return loopMarkerR;
}


/*!
    \fn DrawSoundWidget::getBeatList()
 */
QValueList <long> DrawSoundWidget::getBeatList()
{
    QValueList<long> result=toArray(beatLines)+toArray(lockedBeatLines);
    qHeapSort(result);
    return result;
}


/*!
    \fn DrawSoundWidget::getAssignableBeatLine(QPoint pos)
 */
BeatLine* DrawSoundWidget::getAssignableBeatLine(QPoint pos)
{
    QPtrListIterator<BeatLine> it2( lockedBeatLines );
    BeatLine *beatline;
    while ( (beatline = it2.current()) != 0 ) {
            ++it2;
            if(beatline->getMidiNoteHandle()->contains(pos)) return beatline;
    }
    return 0;
}
