/***************************************************************************
 *   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 "freecycle.h"

#include <qimage.h>
#include <qslider.h>
#include <qlayout.h>
#include <qpixmap.h>
#include <qtoolbar.h>
#include <qtoolbutton.h>
#include <qpopupmenu.h>
#include <qmenubar.h>
#include <qtextedit.h>
#include <qfile.h>
#include <qfiledialog.h>
#include <qstatusbar.h>
#include <qmessagebox.h>
#include <qprinter.h>
#include <qapplication.h>
#include <qaccel.h>
#include <qtextstream.h>
#include <qpainter.h>
#include <qpaintdevicemetrics.h>
#include <qhbox.h>
#include <qpicture.h>
#include <qwhatsthis.h>
#include <qvbox.h>
#include <qcanvas.h>
#include <iostream.h>
#include 	<fcntl.h>
#include 	<sys/ioctl.h>
#include 	<sys/soundcard.h>
#include 	<string.h>
#include <unistd.h>
#include <qspinbox.h>


#include "pics/filesave.xpm"
#include "pics/fileopen.xpm"
#include "pics/icons.h"

Freecycle::Freecycle()
    : QMainWindow( 0, release, WDestructiveClose )
{
    QDir freecycle_dir(QDir::homeDirPath().append("/.freecycle"));
    if (!freecycle_dir.exists()) freecycle_dir.mkdir(freecycle_dir.absPath());

    soundManager=new SoundManager();
    soundManager->loadEffects();
    fileManager=new FileManager();
    soundManager->setFileManager(fileManager);
    midiManager=new MidiManager();
    akpManager=new AKPManager();

    QPixmap openIcon, saveIcon, printIcon;
    openIcon = QPixmap( fileopen );
    saveIcon = QPixmap( filesave );
    QMimeSourceFactory::defaultFactory()->setPixmap( "fileopen", openIcon );
    QPopupMenu * file = new QPopupMenu( this );
    menuBar()->insertItem( tr("&File"), file );

    file->insertItem( openIcon, tr("&Open..."),
			   this, SLOT(choose()), CTRL+Key_O );

    file->insertItem( saveIcon, tr("&Save"),
			   this, SLOT(save()), CTRL+Key_S );

    file->insertItem( tr("Save &As..."), this, SLOT(saveAs()) );
    file->insertItem( tr("Save Chunks..."), this, SLOT(saveChunks()) );

    file->insertSeparator();

    file->insertItem( tr("&Close"), this, SLOT(close()), CTRL+Key_W );

    //file->insertItem( tr("&Quit"), qApp, SLOT( closeAllWindows() ), CTRL+Key_Q );
    file->insertItem( tr("&Quit"), this, SLOT( close()), CTRL+Key_Q );

    menuBar()->insertSeparator();

    QPopupMenu* editPopupMenu = new QPopupMenu( this );
    editPopupMenu->insertItem( tr("Crop"), this, SLOT(cropSelection()) );
    //editPopupMenu->insertItem( tr("Undo"), this, SLOT(undo()), CTRL+Key_Z);
    //editPopupMenu->insertItem( tr("Redo"), this, SLOT(redo()), CTRL+Key_R);
    menuBar()->insertItem( tr("&Edit"), editPopupMenu,1);
    menuBar()->setItemEnabled(1,FALSE);

    QPopupMenu* effectsPopupMenu = new QPopupMenu( this );
    effectsPopupMenu->insertItem( tr("Add LADSPA Plugin..."), this, SLOT(addEffect()) );
    effectsPopupMenu->insertItem( tr("Remove LADSPA Plugin"), this, SLOT(removeEffect()) );
    menuBar()->insertItem( tr("&Effects"), effectsPopupMenu,2);
    menuBar()->setItemEnabled(2,FALSE);


    configureAnalysisPopupMenu = new QPopupMenu( this );
    configureAnalysisPopupMenu->insertItem(tr("Amplitude Domain"),this,SLOT(setAmplitudeDomain()),0,1);
    configureAnalysisPopupMenu->insertItem(tr("Frequency Domain (Experimental)"),this,SLOT(setFrequencyDomain()),0,2);

#ifdef HAS_AUBIO
    configureAnalysisPopupMenu->insertItem(tr("(Aubio) Complex domain"),this,SLOT(setComplexDomain()),0,3);
    configureAnalysisPopupMenu->insertItem(tr("(Aubio) Phase based"),this,SLOT(setPhaseDomain()),0,4);
    configureAnalysisPopupMenu->insertItem(tr("(Aubio) Spectral difference"),this,SLOT(setSpectralDomain()),0,5);
    configureAnalysisPopupMenu->insertItem(tr("(Aubio) High Frequency Content"),this,SLOT(setHFCDomain()),0,6);
    configureAnalysisPopupMenu->setItemEnabled(5,FALSE);

#endif // HAS_AUBIO
    configureAnalysisPopupMenu->setItemChecked(1,TRUE);
    configureAnalysisPopupMenu->insertSeparator();
#ifdef HAS_AUBIO
    configureAnalysisPopupMenu->insertItem(tr("DerivateSignal"),this,SLOT(setDerivateSignal()),0,7);
    configureAnalysisPopupMenu->setItemChecked(7,FALSE);
#else
    configureAnalysisPopupMenu->insertItem(tr("DerivateSignal"),this,SLOT(setDerivateSignal()),0,3);
    configureAnalysisPopupMenu->setItemChecked(3,FALSE);
#endif // HAS_AUBIO







    QPopupMenu* configurationPopupMenu=new QPopupMenu(this);
    configurationPopupMenu->insertItem( tr("Analysis method"),configureAnalysisPopupMenu,1);
    fftDialog=new FFTDialog(soundManager,this);
    configurationPopupMenu->insertItem(tr("Configure FFT ..."),this,SLOT(configureFFT()));
    ampDomainDialog=new AmpDomainDialog(soundManager,this);
    configurationPopupMenu->insertItem(tr("Configure Amplitude domain ..."),this,SLOT(configureAmpDomain()));


    menuBar()->insertItem( tr("&Configuration"), configurationPopupMenu,3);
    menuBar()->setItemEnabled(3,FALSE);




    resize( 800, 600 );





    centralLayout=new QVBox(this);
    centralLayout->setSpacing(5);
    setCentralWidget(centralLayout);

    //Top status bar
    topBox=new QHBox(centralLayout,"File info");
    topBox->setSpacing(10);
    topBox->setMaximumHeight(50);
    topBox->setFrameStyle(QFrame::Panel | QFrame::Raised);
    topBox->hide();
    samplerateLabel=new QLabel(topBox);
    nbframesLabel=new QLabel(topBox);
    channelsLabel=new QLabel(topBox);
    zoomRatioLabel=new QLabel(topBox);
    zoomRatioLabel->hide();
    bpmLabel=new QLabel(topBox);
    //bpmModifSpin=new BPMModifierSpinBox(topBox);
    //connect(bpmModifSpin,SIGNAL(valueChanged(int)),this,SLOT(bpmModifierValueChanged()));
    bpmModifDropDown=new BPMModifierDropDown(topBox);
    connect(bpmModifDropDown,SIGNAL(valueChanged()),this,SLOT(bpmModifierValueChanged()));


    resampleButton=new QPushButton("time stretch to:",topBox,"resample button");

    newBPM=new FloatSpinBox(topBox);
    newBPM->setMinValue(300);
    newBPM->setMaxValue(3000);



    //End Top status Bar
    playAndBeatLinesControls=new QHBox(centralLayout,"Play and BeatLines");
    playAndBeatLinesControls->setSpacing(10);
    playAndBeatLinesControls->setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Minimum);
    playAndBeatLinesControls->hide();
    //Play buttons bar
    playButtons=new QHBox(playAndBeatLinesControls,"Play buttons");
    playButtons->setMaximumHeight(50);
    playButtons->setFrameStyle(QFrame::Panel | QFrame::Raised);
    playButtons->setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Minimum);

    playButton=new QPushButton(">",playButtons);
    playButton->setAccel(Key_Enter);
    playButton->setPixmap(QPixmap(qembed_findImage("player_play")));
    playButton->setToggleButton(TRUE);
    connect(playButton, SIGNAL(clicked()),SLOT(play()));

    pauseButton=new QPushButton("||",playButtons);
    pauseButton->setPixmap(QPixmap(qembed_findImage("player_pause")));
    pauseButton->setToggleButton(TRUE);
    connect(pauseButton, SIGNAL(clicked()),SLOT(pause()));

    stopButton=new QPushButton("S",playButtons);
    stopButton->setAccel(Key_0);
    stopButton->setPixmap(QPixmap(qembed_findImage("player_stop")));
    stopButton->setToggleButton(TRUE);
    stopButton->setOn(TRUE);
    connect(stopButton, SIGNAL(clicked()),SLOT(stopPlay()));

    /*
    loopCheckBox=new QCheckBox("Loop",playButtons);
    loopCheckBox->setPixmap(QPixmap(qembed_findImage("loop")));
    connect(loopCheckBox, SIGNAL(toggled(bool)),SLOT(toggleLoop(bool)));
    */
    loopToggle=new QPushButton("Loop",playButtons);
    loopToggle->setToggleButton(TRUE);
    loopToggle->setPixmap(QPixmap(qembed_findImage("reload")));
    loopToggle->setAccel(Key_Slash);
    connect(loopToggle, SIGNAL(toggled(bool)),SLOT(toggleLoop(bool)));

    playButtons->setSpacing(1);

    //End Play buttons bar

    beatLinesControl=new QHBox(playAndBeatLinesControls,"BeatLine controls");
    beatLinesControl->setFixedHeight(50);
    beatLinesControl->setFrameStyle(QFrame::Panel | QFrame::Raised);
    beatLinesControl->setSpacing(5);
    beatLinesControl->setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Fixed);

    tresholdSlider=new VolumeSlider(beatLinesControl);
    tresholdSlider->setOrientation(Qt::Horizontal);
    tresholdSlider->setMinValue(11);
    tresholdSlider->setMaxValue(200);
    tresholdSlider->setValue(160);
    tresholdSlider->setTickmarks(QSlider::Both);
    tresholdSlider->setTickInterval(10);
    tresholdSlider->setLineStep(1);
    tresholdSlider->setPageStep(10);
    tresholdSlider->setMaximumWidth(200);
    connect(tresholdSlider, SIGNAL(sliderReleased()), SLOT(changeTreshold()) );

    analyseWindowDivider=new QSlider(beatLinesControl);
    analyseWindowDivider->setMinValue(0);
    analyseWindowDivider->setMaxValue(4);
    analyseWindowDivider->setValue(2);
    analyseWindowDivider->setTickmarks(QSlider::Both);
    analyseWindowDivider->setTickInterval(1);
    analyseWindowDivider->setLineStep(1);
    analyseWindowDivider->setPageStep(1);
    analyseWindowDivider->setMaximumHeight(beatLinesControl->height());
    analyseWindowDivider->hide();//not needed
    connect(analyseWindowDivider, SIGNAL(sliderMoved(int)), SLOT(changeWindowDivider(int)) );

    viewOnly=new QPushButton("view only",beatLinesControl);
    viewOnly->setToggleButton(TRUE);
    viewOnly->setPixmap(QPixmap(qembed_findImage("frame_edit")));
    viewOnly->hide(); //not well implemented



    unlockBeatLinesButton=new QPushButton("Unlock All",beatLinesControl);
    unlockBeatLinesButton->setPixmap(QPixmap(qembed_findImage("decrypted-22")));

    lockBeatLinesButton=new QPushButton("Lock All",beatLinesControl);
    lockBeatLinesButton->setPixmap(QPixmap(qembed_findImage("encrypted-22")));

    envelopeControllerWidget=new EnvelopeControllerWidget(playAndBeatLinesControls);
    envelopeControllerWidget->setFixedHeight(50);
    envelopeControllerWidget->setFixedWidth(350);
    envelopeControllerWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
    envelopeControllerWidget->setSpacing(5);
    envelopeControllerWidget->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Fixed);
    //envelopeControllerWidget->hide(); //for now..
    connect(envelopeControllerWidget,SIGNAL(envelopeChanged(EnvelopeData* )),
            soundManager,SLOT(envelopeChanged(EnvelopeData* )));


    big_and_small_wave_and_effects=new MySplitter(Qt::Vertical,centralLayout);
    //big_and_small_wave_and_effects->setOpaqueResize(TRUE);

    MySplitter* big_and_small_wave=new MySplitter(Qt::Vertical,big_and_small_wave_and_effects);
    big_and_small_wave_and_effects->setResizeMode(big_and_small_wave,QSplitter::Auto);

    QVBox* big_wave_and_zoom=new QVBox(big_and_small_wave);

    MySplitter* big_wave_and_env=new MySplitter(Qt::Vertical,big_wave_and_zoom);
    big_wave_and_env->setHandleWidth(2);

    drawSoundWidget=new DrawSoundWidget(big_wave_and_env,"central wave",soundManager);
    drawSoundWidget->enableClipper(TRUE);

    bpmLines=new QPushButton("bpm lines",topBox);
    bpmLines->setToggleButton(TRUE);
    bpmLines->setPixmap(QPixmap(qembed_findImage("kalarm")));
    bpmLines->setDisabled(TRUE);
    connect(drawSoundWidget,SIGNAL(hasLockedBeatLines(bool)),bpmLines,SLOT(setEnabled(bool)));

    envelopeHolder=new EnvelopeHolder(big_wave_and_env);
    envelopeHolder->setMaximumHeight(55);
    envelopeHolder->setMinimumHeight(55);
    envelopeHolder->hide();
    connect(drawSoundWidget,
            SIGNAL(contentsMoving(int,int)),
            envelopeHolder,SLOT(setContentsPos(int,int)));
    connect(drawSoundWidget,
            SIGNAL(receivedEnvelope(QPoint,QString)),
            envelopeHolder,SLOT(setEnvelopeAt(QPoint,QString)));
    connect(drawSoundWidget,SIGNAL(zoomChangedS(long)),
            envelopeHolder,SLOT(setZoomRatio(long)));
    connect(soundManager,SIGNAL(nbFramesChanged(long)),
            envelopeHolder,SLOT(setFrames(long)));
    //envelopeHolder->setHeight(0);

    zoomBox=new QHBox(big_wave_and_zoom);
    zoomBox->setSpacing(10);
    zoomBox->setMaximumHeight(50);
    zoomBox->setFrameStyle(QFrame::Panel | QFrame::Raised);
    zoomBox->hide();

    zoomSlider=new VolumeSlider(zoomBox);
    zoomSlider->setOrientation(Qt::Horizontal);
    zoomSlider->setMinValue(1);
    zoomSlider->setTickmarks(QSlider::Both);
    zoomSlider->setTickInterval(10000);
    zoomSlider->setLineStep(10);
    zoomSlider->setPageStep(10);
    connect(zoomSlider, SIGNAL(sliderReleased()), SLOT(changeZoom()));
    //connect(zoomSlider, SIGNAL(valueChanged(int)), SLOT(changeZoom()));

    zoomToSelButton=new QPushButton("zoom to sel",zoomBox);
    zoomToSelButton->setPixmap(QPixmap(qembed_findImage("viewmagfit")));
    connect(zoomToSelButton,SIGNAL(clicked()),SLOT(zoomToSel()));

    zoomAllButton=new QPushButton("zoom all",zoomBox);
    zoomAllButton->setPixmap(QPixmap(qembed_findImage("viewmag1")));
    connect(zoomAllButton,SIGNAL(clicked()),SLOT(zoomAll()));

    connect(unlockBeatLinesButton,
                    SIGNAL(clicked()),drawSoundWidget,SLOT(unlockBeatLines()));
    connect(lockBeatLinesButton,
            SIGNAL(clicked()),drawSoundWidget,SLOT(lockBeatLines()));
    connect(bpmLines,
                    SIGNAL(toggled(bool)),drawSoundWidget,SLOT(setBPMLines(bool)));



    connect(drawSoundWidget,
                    SIGNAL(bpmChange(const QString &)),
                    bpmLabel,SLOT(setText(const QString &)));

    connect(drawSoundWidget,
                    SIGNAL(loopChange()),
                    this,SLOT(loopChanged()));



    connect(newBPM,
                    SIGNAL(valueChanged(const QString &)),
                    drawSoundWidget,SLOT(computeNewBPMLines(const QString &)));
    connect(resampleButton,
                      SIGNAL(clicked()),drawSoundWidget,SLOT(resample()));
    MySplitter *small_waveAndSpectrum = new MySplitter(Qt::Horizontal, big_and_small_wave );
    small_waveAndSpectrum->setOpaqueResize(TRUE);

    scopeView=new ScopeView(small_waveAndSpectrum);
    scopeView->setSoundManager(soundManager);

    big_and_small_wave->setResizeMode(small_waveAndSpectrum,QSplitter::FollowSizeHint);
    big_and_small_wave->setResizeMode(big_wave_and_zoom,QSplitter::Auto);


    drawAllSoundWidget=new DrawAllSoundWidget(small_waveAndSpectrum,
                                                                                            "small wave", soundManager);


    connect(drawSoundWidget,
                    SIGNAL(visibleAreaChanged(long,long)),
                    drawAllSoundWidget,SLOT(visibleAreaChanged(long,long)));

    connect(drawAllSoundWidget,
                    SIGNAL(visibleAreaChangedS(long,long)),
                    drawSoundWidget,SLOT(zoomToSamplePos(long,long)));

    connect(drawSoundWidget,SIGNAL(playFromPoint(long)),this,SLOT(playFromPoint(long)));
    connect(drawSoundWidget,SIGNAL(playFromTo(long,long)),this,SLOT(playFromTo(long,long)));
    connect(drawSoundWidget,SIGNAL(stopPlay()),this,SLOT(stopPlay()));


    spectrumView=new SpectrumView(small_waveAndSpectrum);

    small_waveAndSpectrum->setResizeMode(spectrumView,QSplitter::Stretch);
    small_waveAndSpectrum->setResizeMode(scopeView,QSplitter::Stretch);
    small_waveAndSpectrum->setResizeMode(drawAllSoundWidget,QSplitter::Stretch);
    spectrumView->setSoundManager(soundManager);
    statusBar()->message( tr("Ready"), 2000 );

    soundPlayer= new SoundPlayer();
    soundPlayer->init();
    soundPlayer->setSoundmanager(soundManager);
    soundPlayer->addSoundMonitor(drawSoundWidget); //Why QThread isn't QObject ?!?
    soundPlayer->addSoundMonitor(spectrumView);        //Why QThread isn't QObject ?!?
    soundPlayer->addSoundMonitor(scopeView);        //Why QThread isn't QObject ?!?


    centralLayout->hide();
    ladspaDialog=new LADSPADialog(this);
    connect(ladspaDialog,SIGNAL(addEffect(int )),this,SLOT(addEffectFrame(int)));
    effectFrame=NULL;



    //connect(soundManager,SIGNAL(waveChanged()),this,SLOT(repaint()));  //why have I done this ?!

    connect(soundManager,SIGNAL(waveChanged()),drawSoundWidget,
                                                SLOT(zapWaveCanvasBuffers()));
    connect(soundManager,SIGNAL(waveChanged()),drawAllSoundWidget,
                                                SLOT(zapWaveCanvasBuffers()));
    connect(soundManager,SIGNAL(waveChanged(long,long)),
            drawSoundWidget,SLOT(zapWaveCanvasBuffers(long,long)));
    connect(soundManager,SIGNAL(waveChanged(long,long)),
            drawAllSoundWidget,SLOT(zapWaveCanvasBuffers(long,long)));

    connect(soundManager,SIGNAL(nbFramesChanged(long)),this,SLOT(updateNbFramesLabel()));
    connect(soundManager,SIGNAL(cropped(long,long)),drawSoundWidget,SLOT(cropped(long,long)));
    connect(soundManager,SIGNAL(cropped(long,long)),drawAllSoundWidget,SLOT(cropped()));
    connect(soundManager,SIGNAL(cropped(long,long)),this,SLOT(cropped(long,long)));

    connect(soundManager,SIGNAL(fftParamsChanged()),drawSoundWidget,
                                                    SLOT(zapWaveCanvasBuffers()));
    connect(soundManager,SIGNAL(analysisParamsChanged()),drawSoundWidget,SLOT(reinitCanvas()));


    configureViewPopupMenu = new QPopupMenu( this );
    configureViewPopupMenu->insertItem( tr("Wave"), this, SLOT(setWaveView()),0,1);
    configureViewPopupMenu->setItemChecked(1,TRUE);
    configureViewPopupMenu->insertItem( tr("Spectrum"), this, SLOT(setSpectrumView()),0,2);
    configureViewPopupMenu->insertSeparator(3);
    configureViewPopupMenu->insertItem( tr("Show BeatLines"), this, SLOT(showBeatLines()),0,4);
    configureViewPopupMenu->setItemChecked(4,TRUE);
    menuBar()->insertItem( tr("&View"), configureViewPopupMenu,4);
    menuBar()->setItemEnabled(4,FALSE);

    QPopupMenu* helpPopupMenu=new QPopupMenu( this );
    helpPopupMenu->insertItem( tr("About"),this,SLOT(about()));
    menuBar()->insertItem( tr("&Help"), helpPopupMenu,5);

    openFileDialog=new MyOpenFileDialog(soundManager,soundPlayer,fileManager);
    saveFileDialog=new MySaveFileDialog();




    QAccel *accelerator = new QAccel( this );        // create accels for myWindow
    accelerator->connectItem( accelerator->insertItem(Key_Space),
                    this,
                    SLOT(spaceBarPressed()));
    accelerator->connectItem( accelerator->insertItem(Key_7),
                    this,
                    SLOT(numPad7Pressed()));
    accelerator->connectItem( accelerator->insertItem(Key_9),
                    this,
                    SLOT(numPad9Pressed()));
    accelerator->connectItem( accelerator->insertItem(Key_1),
                    this,
                    SLOT(numPad1Pressed()));

    //midiOutputThread=new MidiOutputThread();
    //midiOutputThread->start();

    connect(drawSoundWidget,SIGNAL(beatLinesChanged(QValueList< long > )),
        soundManager,SLOT(beatLinesChanged(QValueList< long > )));
connect(drawSoundWidget,SIGNAL(lockedBeatLinesChanged(QValueList< long > )),
        soundManager,SLOT(lockedBeatLinesChanged(QValueList< long > )));
}

void Freecycle::changeZoom(int value){
	long zoomRatioDSW=(long)((double)soundManager->getFrames()/
                                                    ((double) value+drawSoundWidget->width()));
        drawSoundWidget->zoomToSamplePos(
                drawSoundWidget->getFirstVisibleSampleAfterZoom(zoomRatioDSW),
                drawSoundWidget->getLastVisibleSampleAfterZoom(zoomRatioDSW));
	zoomRatioLabel->setText(tr("zoom: %1 - %2").arg(zoomRatioDSW).arg(value));
}

void Freecycle::changeZoom(){
        changeZoom(zoomSlider->value());
}

void Freecycle::changeTreshold(int value){
	drawSoundWidget->setTreshold(value,viewOnly->isOn());
}

void Freecycle::changeTreshold(){
	drawSoundWidget->setTreshold(tresholdSlider->value(),viewOnly->isOn());
}



Freecycle::~Freecycle()
{

}




void Freecycle::choose()
{
    stopPlay();
    soundPlayer->removeSoundMonitor(drawSoundWidget); //Why QThread isn't QObject ?!?
    soundPlayer->removeSoundMonitor(spectrumView);        //Why QThread isn't QObject ?!?
    soundPlayer->removeSoundMonitor(scopeView);        //Why QThread isn't QObject ?!?
    QString fn=NULL;
     if ( openFileDialog->exec() == QDialog::Accepted )
            fn=openFileDialog->selectedFile();
    /*
    QString fn = QFileDialog::getOpenFileName( QString::null,
    						"Sound files ( *.wav , *.aiff )",
						this);
    */
     if ( !fn.isEmpty() ){
	load( fn );
     }else
	statusBar()->message( tr("Loading aborted"), 2000 );

    soundPlayer->addSoundMonitor(drawSoundWidget); //Why QThread isn't QObject ?!?
    soundPlayer->addSoundMonitor(spectrumView);        //Why QThread isn't QObject ?!?
    soundPlayer->addSoundMonitor(scopeView);        //Why QThread isn't QObject ?!?
}


void Freecycle::load( const QString &fileName )
{
        QFile f( fileName );
        if ( !f.open( IO_ReadOnly ) )	return;
        setCaption(release+QString(" - ")+fileName);

        removeEffect();
        fileManager->setFilename(fileName);
        soundManager->loadFile();
        soundManager->setHasEnvelope(FALSE);
        soundManager->setHasEnvelope(TRUE);
        soundPlayer->initLoop();
        soundPlayer->setPosition(0);

        zoomSlider->setValue(1);

        long zoomRatioDSW=(long)(soundManager->getFrames()/
                                                drawSoundWidget->visibleWidth());
        long zoomRatioDASW=(long)(soundManager->getFrames()/
                                                drawAllSoundWidget->visibleWidth());

        drawSoundWidget->setZoomRatio(zoomRatioDSW);
        drawAllSoundWidget->setZoomRatio(zoomRatioDASW);

        drawSoundWidget->fileLoaded();
        drawAllSoundWidget->fileLoaded();

        statusBar()->message( tr("Loaded document %1").arg(fileName), 2000 );


        samplerateLabel->setText(tr("samplerate: %1 Hz").arg(soundManager->getRate()));
        nbframesLabel->setText(tr("frames: %1").arg(soundManager->getFrames()));
        channelsLabel->setText(tr("channels: %1").arg(soundManager->getChannels()));
        zoomRatioLabel->setText(tr("zoom: %1 - %2").arg(zoomRatioDSW).arg(1));
        drawSoundWidget->unlockBeatLines();






        zoomSlider->setMaxValue(soundManager->getFrames()/2);



        menuBar()->setItemEnabled(1,TRUE);
        menuBar()->setItemEnabled(2,TRUE);
        menuBar()->setItemEnabled(3,TRUE);
        menuBar()->setItemEnabled(4,TRUE);
        menuBar()->setItemEnabled(5,TRUE);

        if(effectFrame) effectFrame->reinit();
        if(!topBox->isVisible()) topBox->show();
        if(!playAndBeatLinesControls->isVisible()) playAndBeatLinesControls->show();
        if(!zoomBox->isVisible()) zoomBox->show();
        if(!centralLayout->isVisible()) centralLayout->show();
        soundPlayer->setPosition(0);
        soundManager->envelopeChanged(envelopeControllerWidget->getEnvData());
}

void Freecycle::playFromPoint(long x){
    soundPlayer->setOneTimeLoop(x,soundManager->getFrames()-1);
    play();
    soundPlayer->setPosition(x);
}

void Freecycle::playFromTo(long x1,long x2){
    soundPlayer->setOneTimeLoop(x1,x2);
    soundPlayer->setPlayingOnce(TRUE);
    play();
    soundPlayer->setPosition(x1);
}

void Freecycle::play(){
            if(soundPlayer->getOutputType()==SoundPlayer::OUTPUT_DEVDSP){
                if(!soundPlayer->running())
                    soundPlayer->start();
            }
            soundPlayer->setPlaying(TRUE);
            pauseButton->setOn(FALSE);
            stopButton->setOn(FALSE);
            playButton->setOn(TRUE);
            //midiOutputThread->continueQueue();
}

void Freecycle::pause(){
        soundPlayer->setPlaying(FALSE);
        playButton->setOn(FALSE);
        stopButton->setOn(FALSE);
        pauseButton->setOn(TRUE);
        //midiOutputThread->stopQueue();
}

void Freecycle::stopPlay(){
        soundPlayer->stopPlay();
        playButton->setOn(FALSE);
        pauseButton->setOn(FALSE);
        stopButton->setOn(TRUE);
        soundPlayer->resetLoop();
        //midiOutputThread->stopQueue();
}


void Freecycle::save()
{
    QString filename=fileManager->getOriginalFilename();
    if(filename){
        soundManager->saveSoundBufferTo(filename,SoundHolder::FOR_OUTPUT);
        statusBar()->message( tr( "File %1 saved" ).arg( filename ), 2000 );
    }else{
        statusBar()->message( tr( "Save what?!" ), 2000 );
    }
}


void Freecycle::saveAs()
{
    QString filename=QString::null;
    if(soundManager->hasSound()) filename=fileManager->getOriginalFilename();

    QString fn = QFileDialog::getSaveFileName( filename, QString::null,
					       this );

    if ( !fn.isEmpty() ) {
        soundManager->saveSoundBufferTo(fn,SoundHolder::FOR_OUTPUT);
        statusBar()->message( tr( "File %1 saved" ).arg( fn), 2000 );
    } else {
	statusBar()->message( tr("Saving aborted"), 2000 );
    }
}


void Freecycle::saveChunks()
{
    int size=drawSoundWidget->getNbBeats();
    if(size==0){
        QMessageBox::critical(this,"Problem!","No beatlines, no chunks! (:P)",0);
    }else{
        QString fn=NULL;
        saveFileDialog->setBps(soundManager->getBps());
        if ( saveFileDialog->exec() == QDialog::Accepted )
            fn=saveFileDialog->selectedFile();
        if ( !fn.isEmpty() ) {
            QMemArray <long>beatlines(0);
            long* temp=new long[size];
            drawSoundWidget->getBeats(temp);
            std::sort(&temp[0],&temp[size-1]);
            if(saveFileDialog->exportMode()==MySaveFileDialog::EXPORT_LOOP){
                if(drawSoundWidget->hasLoopSet()){
                    long left=drawSoundWidget->getLeftLoopMarkerSample();
                    long right=drawSoundWidget->getRightLoopMarkerSample();
                    for (int i=0;i<size;i++){
                        if(temp[i]>=left && temp[i]<=right){
			/*
                            if(beatlines.size()==0 && temp[i]!=left){ //include left marker if not present
                                beatlines.resize(beatlines.size()+1);
                                beatlines[beatlines.size()-1]=left;
				cout<<"included: "<<left<<endl;
                            }
			    */
                            beatlines.resize(beatlines.size()+1);
                            beatlines[beatlines.size()-1]=temp[i];
			    cout<<"included: "<<temp[i]<<endl;
                        }
                    }
		    /*
                    if(beatlines[beatlines.size()-1]!=right){ //include right marker if not present
                        beatlines.resize(beatlines.size()+1);
                        beatlines[beatlines.size()-1]=right;
			cout<<"included: "<<right<<endl;
                    }
		    */
                }else{
                    QMessageBox::critical(this,"Problem!","Invalid loop!",0);
                    return;
                }
            }else{
                beatlines.assign(temp,size);
                std::sort(&beatlines[0],&beatlines[size-1]);
                if(beatlines[0]!=0){ //include first frame if not present
                    beatlines.resize(beatlines.size()+1);
                    beatlines[beatlines.size()-1]=0;
                    std::sort(&beatlines[0],&beatlines[size-1]);
                }
                if(beatlines[size-1]!=soundManager->getFrames()-1){ //include last frame if not present
                    beatlines.resize(beatlines.size()+1);
                    beatlines[beatlines.size()-1]=soundManager->getFrames()-1;
                    std::sort(&beatlines[0],&beatlines[size-1]);
                }
            }
            cout<<"Export bits per sample: "<<saveFileDialog->getExportBitsPerSample()<<" code: "<<soundManager->toBpsCode(saveFileDialog->getExportBitsPerSample())<<"\n";
            if(saveFileDialog->getAttackTime()!=0){
                Envelope* env=new Envelope();
                env->setEnvDurationAndSamplerate(saveFileDialog->getAttackTime(),soundManager->getRate());
                soundManager->addPostProcessEffect(env);
            }
            QStringList* filenames=
                soundManager->saveChunksTo(fn,beatlines.data(),beatlines.size(),
                                     soundManager->toBpsCode(saveFileDialog->getExportBitsPerSample()));
            if(saveFileDialog->exportMidifile()){
                midiManager->writeMidiFile(fn,beatlines.data(),
                                                                    beatlines.size(),drawSoundWidget->getUsedBPM());
            }
            if(saveFileDialog->exportAKP()){
                akpManager->writeAKPFile(fn,filenames);
            }
            statusBar()->message( tr( "File %1 saved to chunks" ).arg( fn), 2000 );
            delete filenames;
        } else {
            statusBar()->message( tr("Saving aborted"), 2000 );
        }
    }
}




void Freecycle::closeEvent( QCloseEvent* ce )
{
        if(soundPlayer->running()){
            soundPlayer->exit(0);
        }
        delete soundPlayer;
        delete fileManager;
        ce->accept();
	return;
}


void Freecycle::about()
{
    QMessageBox::information( this, tr("Freecycle alpha 0.1"),
			tr("Developped under GNU Public Licence by:"
                        "\nPredrag Viceic <viceic@net2000.ch>"
                        "\n\nCredits:\n\n"
                        "JACK layer  and LADSPA control port init taken from the AlsaModularSynth project by Matthias Nagorni"
                            "\nhttp://alsamodular.sourceforge.net/\n\n"
                        "/dev/dsp layer borrowed from the libsndfile examples by Erik de Castro Lopo\n"
                            "http://www.mega-nerd.com/libsndfile/\n\n"
                        "Midi file generation code stolen from the Waon project\n"
                            "Copyright (C) 1998 Kengo ICHIKI (ichiki@geocities.com)\n\n"
                        "Beat analysis algorithms inspired on the [not fully understood] paper by Frederic Patin\n"
                            "http://www.yov408.com/\n\n"
                        "Aubio support by Piem\n"
                                "<piem@altern.org>\n\n"
                        "AKP export implementation based on the specifications by Seb Francis\n"
                            "http://www.sonicspot.com/guide/AKPspec.html\n\n"
                        "Icons from Crystal SVG Icon Theme by Everaldo\n"
                            "http://www.everaldo.com\n"
                            "(Icon modifications by me)")
                        ,"Enjoy!");
}





/*!
    \fn Freecycle::zoomToSel()
 */
void Freecycle::zoomToSel()
{
    long newZoomRatio=drawSoundWidget->zoomToSel();
    int newZoomSliderValue=(soundManager->getFrames()-(width()*newZoomRatio))/newZoomRatio;
    zoomSlider->blockSignals(true);
    zoomSlider->setValue(newZoomSliderValue);
    zoomSlider->blockSignals(false);
}


/*!
    \fn Freecycle::zoomAll()
 */
void Freecycle::zoomAll()
{
    long newZoomRatio=drawSoundWidget->zoomAll();
    //drawAllSoundWidget->zoomAll();
    int newZoomSliderValue=(soundManager->getFrames()-(width()*newZoomRatio))/newZoomRatio;
    zoomSlider->blockSignals(true);
    zoomSlider->setValue(newZoomSliderValue);
    zoomSlider->blockSignals(false);
}


/*!
    \fn Freecycle::changeWindowDivider(int)
 */
void Freecycle::changeWindowDivider(int value)
{
    drawSoundWidget->setWindowDivider(value,viewOnly->isOn());
}




void Freecycle::cropSelection(){
    long start=drawSoundWidget->getSelectionStartSample();
    long end=drawSoundWidget->getSelectionEndSample();
    if(start!=end && start!=-1 && end!=-1){
        soundManager->crop(start,end);
        //zoomAll();
        //drawSoundWidget->reinitCanvas();
    }
}

void Freecycle::undo(){
    if(soundManager->previousSoundBuffer(SoundHolder::ORIGINAL_WAVE)){
        zoomAll();
        drawSoundWidget->forceRepaint();
        drawAllSoundWidget->forceRepaint();
        drawSoundWidget->reinitCanvas();
    }
    repaint();
}

void Freecycle::redo(){
    if(soundManager->nextSoundBuffer()){
        zoomAll();
        drawSoundWidget->forceRepaint();
        drawAllSoundWidget->forceRepaint();
        drawSoundWidget->reinitCanvas();
    }
    repaint();
}

void Freecycle::addEffect(){
    ladspaDialog->setEffectsList(soundManager->getEffects());
    ladspaDialog->exec();
}

void Freecycle::configureFFT(){
    fftDialog->exec();
}

void Freecycle::configureAmpDomain(){
    ampDomainDialog->exec();
}

void Freecycle::removeEffect(){
    soundManager->setHasLadspa(false);
    if(soundManager->getHasEnvelope())
        soundManager->applyEnvelope();
    else soundManager->zapInstantEBuffer();
    if(effectFrame){
        effectFrame->close();
    }
    drawSoundWidget->zapWaveCanvasBuffers();
    drawAllSoundWidget->zapWaveCanvasBuffers();
}

void Freecycle::addEffectFrame(int uniqueId){

    removeEffect();
    soundManager->setHasLadspa(TRUE);
    LADSPAEffect* temp=soundManager->getEffects()->getEffect(uniqueId);
    effectFrame=new EffectFrame(temp,big_and_small_wave_and_effects);
    big_and_small_wave_and_effects->setResizeMode(effectFrame,QSplitter::Stretch);
    effectFrame->setZoomRatio(drawSoundWidget->getZoomRatio());
    effectFrame->setContentsPos(drawSoundWidget->contentsX(),0);
    connect(effectFrame,SIGNAL(applyMe(LADSPAEffect*)),
                    soundManager,SLOT(applyPlugin(LADSPAEffect* )));
    connect(effectFrame,SIGNAL(applyMe(LADSPAEffect*,long,long)),
                    soundManager,SLOT(applyPlugin(LADSPAEffect*,long,long)));
    connect(drawSoundWidget,SIGNAL(zoomChangedS(long)),
                   effectFrame,SLOT(setZoomRatio(long)));
    connect(drawSoundWidget,
                    SIGNAL(contentsMoving(int,int)),
                    effectFrame,SLOT(setContentsPos(int,int)));
    effectFrame->show();
    effectFrame->apply();
}

void Freecycle::updateNbFramesLabel(){
    nbframesLabel->setText(tr("frames: %1").arg(soundManager->getFrames()));
}

void Freecycle::setAmplitudeDomain(){
    soundManager->setAnalysisMethod(SoundManager::AMP_DOMAIN);
    drawSoundWidget->reinitCanvas();
    configureAnalysisPopupMenu->setItemChecked(1,TRUE);
    configureAnalysisPopupMenu->setItemChecked(2,FALSE);
#ifdef HAS_AUBIO
    configureAnalysisPopupMenu->setItemChecked(3,FALSE);
    configureAnalysisPopupMenu->setItemChecked(4,FALSE);
    configureAnalysisPopupMenu->setItemChecked(5,FALSE);
    configureAnalysisPopupMenu->setItemChecked(6,FALSE);
#endif
}
void Freecycle::setFrequencyDomain(){
    std::cout<<"set freq"<<endl;
    soundManager->setAnalysisMethod(SoundManager::FREQ_DOMAIN);
    drawSoundWidget->reinitCanvas();
    configureAnalysisPopupMenu->setItemChecked(2,TRUE);
    configureAnalysisPopupMenu->setItemChecked(1,FALSE);
#ifdef HAS_AUBIO
    configureAnalysisPopupMenu->setItemChecked(3,FALSE);
    configureAnalysisPopupMenu->setItemChecked(4,FALSE);
    configureAnalysisPopupMenu->setItemChecked(5,FALSE);
    configureAnalysisPopupMenu->setItemChecked(6,FALSE);
#endif
}
#ifdef HAS_AUBIO
void Freecycle::setComplexDomain(){
    std::cout<<"set complex"<<endl;
    soundManager->setAnalysisMethod(SoundManager::COMPLEX_DOMAIN);
    drawSoundWidget->reinitCanvas();
    configureAnalysisPopupMenu->setItemChecked(1,FALSE);
    configureAnalysisPopupMenu->setItemChecked(2,FALSE);
    configureAnalysisPopupMenu->setItemChecked(3,TRUE);
    configureAnalysisPopupMenu->setItemChecked(4,FALSE);
    configureAnalysisPopupMenu->setItemChecked(5,FALSE);
    configureAnalysisPopupMenu->setItemChecked(6,FALSE);
}
void Freecycle::setPhaseDomain(){
    std::cout<<"set phase"<<endl;
    soundManager->setAnalysisMethod(SoundManager::PHASE_DIFF);
    drawSoundWidget->reinitCanvas();
    configureAnalysisPopupMenu->setItemChecked(1,FALSE);
    configureAnalysisPopupMenu->setItemChecked(2,FALSE);
    configureAnalysisPopupMenu->setItemChecked(3,FALSE);
    configureAnalysisPopupMenu->setItemChecked(4,TRUE);
    configureAnalysisPopupMenu->setItemChecked(5,FALSE);
    configureAnalysisPopupMenu->setItemChecked(6,FALSE);
}
void Freecycle::setSpectralDomain(){
    std::cout<<"set spectral"<<endl;
    soundManager->setAnalysisMethod(SoundManager::SPEC_DIFF);
    drawSoundWidget->reinitCanvas();
    configureAnalysisPopupMenu->setItemChecked(1,FALSE);
    configureAnalysisPopupMenu->setItemChecked(2,FALSE);
    configureAnalysisPopupMenu->setItemChecked(3,FALSE);
    configureAnalysisPopupMenu->setItemChecked(4,FALSE);
    configureAnalysisPopupMenu->setItemChecked(5,TRUE);
    configureAnalysisPopupMenu->setItemChecked(6,FALSE);
}
void Freecycle::setHFCDomain(){
        std::cout<<"set hfc"<<endl;
        soundManager->setAnalysisMethod(SoundManager::HFC);
        drawSoundWidget->reinitCanvas();
        configureAnalysisPopupMenu->setItemChecked(1,FALSE);
        configureAnalysisPopupMenu->setItemChecked(2,FALSE);
        configureAnalysisPopupMenu->setItemChecked(3,FALSE);
        configureAnalysisPopupMenu->setItemChecked(4,FALSE);
        configureAnalysisPopupMenu->setItemChecked(5,FALSE);
        configureAnalysisPopupMenu->setItemChecked(6,TRUE);
}
#endif

void Freecycle::setDerivateSignal(){
#ifdef HAS_AUBIO
    if(configureAnalysisPopupMenu->isItemChecked(7))
#else
    if(configureAnalysisPopupMenu->isItemChecked(3))
#endif
    {
    soundManager->setDerivateSignal(FALSE);

#ifdef HAS_AUBIO
    configureAnalysisPopupMenu->setItemChecked(7,FALSE);
#else
    configureAnalysisPopupMenu->setItemChecked(3,FALSE);
#endif

    }else{
        soundManager->setDerivateSignal(TRUE);
#ifdef HAS_AUBIO
     configureAnalysisPopupMenu->setItemChecked(7,TRUE);
#else
       configureAnalysisPopupMenu->setItemChecked(3,FALSE);
#endif
    }
    drawSoundWidget->reinitCanvas();
}


/*!
    \fn Freecycle::toggleLoop(bool)
 */
void Freecycle::toggleLoop(bool toggle)
{
     if(toggle && drawSoundWidget->hasLoopSet()){
            soundPlayer->setLoop(drawSoundWidget->getLeftLoopMarkerSample(),
                                               drawSoundWidget->getRightLoopMarkerSample());
        }else{
            soundPlayer->setLoop(0,soundManager->getFrames()-1);
        }
}


/*!
    \fn Freecycle::loopChanged()
 */
void Freecycle::loopChanged()
{
    toggleLoop(loopToggle->isOn());
}

void Freecycle::cropped(long start,long end){
    soundPlayer->cropped(start,end);
}



/*!
    \fn Freecycle::setWaveView()
 */
void Freecycle::setWaveView()
{
    drawSoundWidget->getCanvas()->changeViewMode(WaveCanvas::WAVE_VIEWMODE);
    configureViewPopupMenu->setItemChecked(1,TRUE);
    configureViewPopupMenu->setItemChecked(2,FALSE);
}


/*!
    \fn Freecycle::setSpectrumView()
 */
void Freecycle::setSpectrumView()
{
    drawSoundWidget->getCanvas()->changeViewMode(WaveCanvas::SPECTRUM_VIEWMODE);
    configureViewPopupMenu->setItemChecked(2,TRUE);
    configureViewPopupMenu->setItemChecked(1,FALSE);
}


/*!
    \fn Freecycle::showBeatLines()
 */
void Freecycle::showBeatLines()
{
    if(configureViewPopupMenu->isItemChecked(4)){
        drawSoundWidget->showBeatLines(FALSE);
        configureViewPopupMenu->setItemChecked(4,FALSE);
    }else{
        drawSoundWidget->showBeatLines(TRUE);
        configureViewPopupMenu->setItemChecked(4,TRUE);
    }



}



/*!
    \fn Freecycle::bpmModifierValueChanged()
 */
void Freecycle::bpmModifierValueChanged()
{
    drawSoundWidget->setComputedBPMModifier(this->bpmModifDropDown->getModifier());
}


void Freecycle::spaceBarPressed() {
    if(playButton->isOn()) pause();
    else play();
}


/*!
    \fn Freecycle::numPad7Pressed()
 */
void Freecycle::numPad7Pressed()
{
    soundPlayer->setPosition(drawSoundWidget->getLeftLoopMarkerSample());
}


/*!
    \fn Freecycle::numPad9Pressed
 */
void Freecycle::numPad9Pressed()
{
    soundPlayer->setPosition(drawSoundWidget->getRightLoopMarkerSample());
}




/*!
    \fn Freecycle::numPad1Pressed()
 */
void Freecycle::numPad1Pressed()
{
    soundPlayer->setPosition(0);
}
