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


LADSPAPort::LADSPAPort(int _portnumber,QString _name,LADSPA_PortDescriptor _desc,
                                               LADSPA_PortRangeHint _hint,
                                               QObject *parent, const char *name)
 : QObject(parent, name)
{
    descriptor=_desc;
    hint=_hint;
    portname=_name;
    val=1.0;
    portNumber=_portnumber;
    initInputControlPort();
    count=0;
    valuesOverTime=0;
    nbFrames=0;
    connectionMethod=CONNECTION_METHOD_L;
    connectionMethodDouble=CONNECTION_METHOD_L;
    nbValues=0;
}


LADSPAPort::~LADSPAPort()
{
    zaparr(valuesOverTime);
}




/*!
    \fn LADSPAPort::isAudioInput()
 */
bool LADSPAPort::isAudioInput()
{

    return descriptor==(LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO);
}


/*!
    \fn LADSPAPort::isAudioOutput()
 */
bool LADSPAPort::isAudioOutput()
{
    return descriptor==(LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO);
}


/*!
    \fn LADSPAPort::isControlInput()
 */
bool LADSPAPort::isControlInput()
{
    return descriptor==(LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL);
}


/*!
    \fn LADSPAPort::isControlOutput()
 */
bool LADSPAPort::isControlOutput()
{
    return descriptor==(LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL);
}


/*!
    \fn LADSPAPort::initInputControlPorts()
 */
void LADSPAPort::initInputControlPort()
{
    if (isControlInput()) {
         if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor) &&
             val < hint.LowerBound)
            val = hint.LowerBound;

         if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor) &&
             val > hint.UpperBound)
            val = hint.UpperBound;

         if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint.HintDescriptor))
            val = hint.LowerBound;

         if (LADSPA_IS_HINT_DEFAULT_LOW(hint.HintDescriptor))
            val = hint.LowerBound * 0.75f + hint.UpperBound * 0.25f;

         if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint.HintDescriptor))
            val = hint.LowerBound * 0.5f + hint.UpperBound * 0.5f;

         if (LADSPA_IS_HINT_DEFAULT_HIGH(hint.HintDescriptor))
            val = hint.LowerBound * 0.25f + hint.UpperBound * 0.75f;

         if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint.HintDescriptor))
            val = hint.UpperBound;

         if (LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor))
            val *= 44100;

         if (LADSPA_IS_HINT_DEFAULT_0(hint.HintDescriptor))
            val = 0.0f;

         if (LADSPA_IS_HINT_DEFAULT_1(hint.HintDescriptor))
            val = 1.0f;

         if (LADSPA_IS_HINT_DEFAULT_100(hint.HintDescriptor))
            val = 100.0f;

         if (LADSPA_IS_HINT_DEFAULT_440(hint.HintDescriptor))
            val = 440.0f;
      }
}


/*!
    \fn LADSPAPort::getLowerBound()
 */
float LADSPAPort::getLowerBound()
{
    if (LADSPA_IS_HINT_BOUNDED_BELOW(hint.HintDescriptor)){
        if(LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor))
            return hint.LowerBound*44100;
        else
            return hint.LowerBound;
    }else return FLT_MIN;
}


/*!
    \fn LADSPAPort::getUpperBound()
 */
float LADSPAPort::getUpperBound()
{
     if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint.HintDescriptor)){
        if(LADSPA_IS_HINT_SAMPLE_RATE(hint.HintDescriptor))
            return hint.UpperBound*44100;
        else
            return hint.UpperBound;
    }else return FLT_MAX;
}


/*!
    \fn LADSPAPort::setControlInputValue(float)
 */
void LADSPAPort::setControlInputValue(float _val)
{
    if(isControlInput()) val=_val;
}


/*!
    \fn LADSPAPort::getPortNumber()
 */
int LADSPAPort::getPortNumber()
{
    return portNumber;
}


/*!
    \fn LADSPAPort::getICPortValuePointer()
 */
float* LADSPAPort::getCPortValuePointer()
{
    if(isControlInput() || isControlOutput()) return &val;
    else return NULL;
}


/*!
    \fn LADSPAPort::getPortName()
 */
QString LADSPAPort::getPortName()
{
    return portname;
}


/*!
    \fn LADSPAPort::setValuesOverTime(float*)
 */
void LADSPAPort::setValuesOverTime(float* vot)
{
    valuesOverTime=vot;
}

/*!
    \fn LADSPAPort::setValuesOverTime(float*)
 */
void LADSPAPort::advanceValue()
{
    if(areBoundsOk()){
        if(valuesOverTime && count<nbValues){
            val=valuesOverTime[count];
        }
        count++;
    }
}

void LADSPAPort::startValue()
{
    if(areBoundsOk()){
        if(valuesOverTime){
            count=0;
            val=valuesOverTime[0];
        }
    }
}

void LADSPAPort::startValue(int index)
{
    if(areBoundsOk()){
        if(valuesOverTime){
            count=index;
            val=valuesOverTime[index];
        }
    }
}


/*!
    \fn LADSPAPort::setNbFrames(int)
 */
void LADSPAPort::setNbFrames(long nbf)
{
    nbFrames=nbf;
}


/*!
    \fn LADSPAPort::getNbFrames()
 */
long LADSPAPort::getNbFrames()
{
    return nbFrames;
}


/*!
    \fn LADSPAPort::getVOTPointer(long)
 */
float* LADSPAPort::getVOTPointer(long i)
{
    if(areBoundsOk())
        return &(valuesOverTime[i]);
    else return &val;

}

void LADSPAPort::initControlValues(){
    if(areBoundsOk()){
        nbValues=int(ceil(nbFrames/1024));
        valuesOverTime=new float[nbValues];
        for (int i=0;i<nbValues;i++){
            valuesOverTime[i]=val;
            //std::cout<<"vot pointer at "<<i<<" : "<<*getVOTPointer(i)<<"\n";
        }
        std::cout<<"vot init succedded for ["<<nbValues<<"] values \n";
    }
}


/*!
    \fn LADSPAPort::areBoundsOk()
 */
bool LADSPAPort::areBoundsOk()
{
    if(isControlInput()){
        if (getLowerBound()==getUpperBound()) return FALSE;
        else return TRUE;
    }else return FALSE;
}


/*!
    \fn LADSPAPort::setConnectionParam(QString)
 */
void LADSPAPort::setConnectionMethod(const QString& _connParam)
{
    //std::cout<<getPortName()<<" : "<<_connParam<<"\n";
    /*
        dirty.
        Why static const char* CONNECTION_METHOD_L="Wave L" doesn't work?!
    */
    if(_connParam=="Wave L") connectionMethod=CONNECTION_METHOD_L;
    else if(_connParam=="Wave R") connectionMethod=CONNECTION_METHOD_R;
    else if(_connParam=="Wave L + R") connectionMethod=CONNECTION_METHOD_LR;
    else if(_connParam=="Zero") connectionMethod=CONNECTION_METHOD_ZERO;
}

void LADSPAPort::setConnectionMethodDouble(const QString& _connParam)
{
    //std::cout<<getPortName()<<" : "<<_connParam<<"\n";
    /*
        dirty.
        Why static const char* CONNECTION_METHOD_L="Wave L" doesn't work?!
    */
    if(_connParam=="Wave L") connectionMethodDouble=CONNECTION_METHOD_L;
    else if(_connParam=="Wave R") connectionMethodDouble=CONNECTION_METHOD_R;
    else if(_connParam=="Wave L + R") connectionMethodDouble=CONNECTION_METHOD_LR;
    else if(_connParam=="Zero") connectionMethodDouble=CONNECTION_METHOD_ZERO;
}


/*!
    \fn LADSPAPort::getConnectionMethod()
 */
int LADSPAPort::getConnectionMethod()
{
    return connectionMethod;
}

/*!
    \fn LADSPAPort::getConnectionMethodDouble()
 */
int LADSPAPort::getConnectionMethodDouble()
{
    return connectionMethodDouble;
}


/*!
    \fn LADSPAPort::setConnectionMethodDouble(connectionMethod m)
 */
void LADSPAPort::setConnectionMethodDouble(ConnectionMethod m)
{
    connectionMethodDouble=m;
}


/*!
    \fn LADSPAPort::setConnectionMethod(connectionMethod m)
 */
void LADSPAPort::setConnectionMethod(ConnectionMethod m)
{
    connectionMethod=m;
}


/*!
    \fn LADSPAPort::initControlValues(QValueList<float> vals)
 */
void LADSPAPort::initControlValues(QValueList<float> vals)
{
    if(areBoundsOk()){
        valuesOverTime=new float[vals.count()];
        for (uint i=0;i<vals.count();i++){
            valuesOverTime[i]=vals[i];
        }
        std::cout<<"vot init succedded for ["<<vals.count()<<"] values \n";
        nbValues=vals.count();
    }
}


/*!
    \fn LADSPAPort::getPortControlValues()
 */
QValueList<float> LADSPAPort::getPortControlValues()
{
    QValueList<float> values;
    for (int i=0;i<nbValues;i++){
        values.append(valuesOverTime[i]);
    }
    return values;
}


/*!
    \fn LADSPAPort::crop(long start, long end)
 */
void LADSPAPort::crop(long start, long end)
{
    cout<<"cropping VOT\n";
    int length=(int)ceil((end-start)/1024.0);
    float* tempVOT=new float[length];
    memcpy(tempVOT,&valuesOverTime[int(start/1024)],sizeof(float)*length);
    zaparr(valuesOverTime);
    valuesOverTime=tempVOT;
    tempVOT=0;
}


/*!
    \fn LADSPAPort::insert(long start, long amount)
 */
void LADSPAPort::insert(long start, long amount)
{
    cout<<"inserting VOT\n";
    int length=(getNbFrames())/1024; //nb frames is already updated by nbFramesChanged(long) signal..I hope..
    float* tempVOT=new float[length];
    float* insertedVOT=new float[amount/1024];
    for (int i=0;i<amount;i++){
        insertedVOT[i]=val;
    }
    if(start>0) memcpy(tempVOT,valuesOverTime,sizeof(float)*int(start/1024));
    memcpy(&tempVOT[int(start/1024)],insertedVOT,sizeof(float)*amount);
    memcpy(&tempVOT[int((start+amount)/1024)],&valuesOverTime[int(start/1024)],sizeof(float)*(getNbFrames()-start)/1024);
    zaparr(valuesOverTime);
    valuesOverTime=tempVOT;
    tempVOT=0;
}
