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

AKPManager::AKPManager(QObject *parent, const char *name)
 : QObject(parent, name)
{
}


AKPManager::~AKPManager()
{
}

void AKPManager::writeAKPFile(QString outputfileName,QStringList* filenames){
        QFile* outputfile=new QFile(outputfileName+".akp");
        outputfile->open(IO_Raw | IO_ReadWrite);
	char nb_keygroups=filenames->size();
	char loudness=127;
	char velocity_sens=25;
//0000 ->
	outputfile->writeBlock("RIFF",4);
	//outputfile.writeBlock(0x00,1);outputfile.writeBlock(0x00,1);outputfile.writeBlock(0x00,1);outputfile.writeBlock(0x00,1);
        write4Bytes(outputfile);
	outputfile->writeBlock("APRG",4);
	outputfile->writeBlock("prg ",4);
	//outputfile.writeBlock(0x06,1);outputfile.writeBlock(0x00,1);outputfile.writeBlock(0x00,1);outputfile.writeBlock(0x00,1);
        write4Bytes(outputfile,0x06);
        writeByte(outputfile,0x01);
        writeByte(outputfile,0x00);
        writeByte(outputfile,nb_keygroups);//nb of keygroups
        writeByte(outputfile,0x00);
        writeByte(outputfile,0x02);
        writeByte(outputfile,0x00);
//<-0019

//->001A
	outputfile->writeBlock("out ",4);
	write4Bytes(outputfile,0x08);
        QByteArray out_params(8);
	out_params[0]=0x01;
	out_params[1]=loudness; //loudness
	out_params[2]=0x00; //amp mod 1
	out_params[3]=0x00; //amp mod 2
	out_params[4]=0x00; //pan mod 1
	out_params[5]=0x00; //pan mod 2
	out_params[6]=0x00; //pan mod 3
	out_params[7]=velocity_sens; //velocity sens
	outputfile->writeBlock(out_params.data(),out_params.size());
//<-029

//002A->
	outputfile->writeBlock("tune",4);
        write4Bytes(outputfile,0x16);
	QByteArray tune_params(22);
	tune_params[0]=0x01;
	tune_params[1]=0x00; //semitone tune
	tune_params[2]=0x00; //fine tune
         tune_params[3]=0x00; //C detune
	tune_params[4]=0x00; //C# detune
	tune_params[5]=0x00; //D detune
	tune_params[6]=0x00; //Eb detune
	tune_params[7]=0x00; //E detune
	tune_params[8]=0x00; //F detune
	tune_params[9]=0x00; //F# detune
	tune_params[10]=0x00; //G detune
	tune_params[11]=0x00; //G# detune
	tune_params[12]=0x00; //A detune
	tune_params[13]=0x00; //Bb detune
	tune_params[14]=0x00; //B detune
	tune_params[15]=0x02; //Pitchbend Up
	tune_params[16]=0x02; //Pitchbend Down
	tune_params[17]=0x00; //Bend mode
	tune_params[18]=0x00; //Aftertouch
	tune_params[19]=0x00;
	tune_params[20]=0x00;
	tune_params[21]=0x00;
	outputfile->writeBlock(tune_params.data(),tune_params.size());
//<-0047

//0048->
	outputfile->writeBlock("lfo ",4); //Lfo 1
        write4Bytes(outputfile,0x0C);
	QByteArray lfo1_params(12);
	lfo1_params[0]=0x01;
	lfo1_params[1]=0x01; //Waveform
	lfo1_params[2]=43; //rate
	lfo1_params[3]=0x00;//delay
	lfo1_params[4]=0x00;//depth
	lfo1_params[5]=0x00;//LFO sync
	lfo1_params[6]=0x01;
	lfo1_params[7]=0x0F;//Modwheel
	lfo1_params[8]=0x00;//Aftertouch
	lfo1_params[9]=0x00;//rate mod
	lfo1_params[10]=0x00;//delay mod
	lfo1_params[11]=0x00;//depth mod
	outputfile->writeBlock(lfo1_params.data(),lfo1_params.size());
//<-005B

//->005C
        outputfile->writeBlock("lfo ",4); //Lfo 2
        write4Bytes(outputfile,0x0C);
        QByteArray lfo2_params(12);
        lfo2_params[0]=0x01;
        lfo2_params[1]=0x00; //Waveform
        lfo2_params[2]=0x00; //rate
        lfo2_params[3]=0x00;//delay
        lfo2_params[4]=0x00;//depth
        lfo2_params[5]=0x01;
        lfo2_params[6]=0x00; //LFO Re trigger
        lfo2_params[7]=0x00;
        lfo2_params[8]=0x00;
        lfo2_params[9]=0x00;//rate mod
        lfo2_params[10]=0x00;//delay mod
        lfo2_params[11]=0x00;//depth mod
        outputfile->writeBlock(lfo2_params.data(),lfo2_params.size());
//<-006F

//0070->
        outputfile->writeBlock("mods",4);
        write4Bytes(outputfile,0x26);
        QByteArray mods_params(27);
        mods_params[0]=0x01;
        mods_params[1]=0x00;
        mods_params[2]=0x11;
        mods_params[3]=0x00;
        mods_params[4]=0x02;
        mods_params[5]=0x06; //Amp mod 1 src
        mods_params[6]=0x02;
        mods_params[7]=0x03;//Amp mod 2 src
        mods_params[8]=0x01;
        mods_params[9]=0x08;//Pan Mod 1 src
        mods_params[10]=0x01;
        mods_params[11]=0x06;//Pan Mod 2 src
        mods_params[12]=0x01;
        mods_params[13]=0x01;//Pan Mod 3 src
        mods_params[14]=0x04;
        mods_params[15]=0x06;//LFO 1 Rate Mod src
        mods_params[16]=0x05;
        mods_params[17]=0x06;//LFO 1 Delay Mod src
        mods_params[18]=0x03;
        mods_params[19]=0x06;//LFO 1 Depth Mod src
        mods_params[20]=0x07;
        mods_params[21]=0x00;//LFO 2 Rate Mod src
        mods_params[22]=0x08;
        mods_params[23]=0x00;//LFO 2 Delay Mod src
        mods_params[24]=0x06;
        mods_params[25]=0x00;//LFO 2 Depth Mod src
        mods_params[26]=0x00;
        outputfile->writeBlock(mods_params.data(),mods_params.size());
//<-0092

//Keygroup Mod Sources
//0093->
	QByteArray mod_sources_params(11);
	mod_sources_params[0]=0x07;//Pitch Mod 1 Src
	mod_sources_params[1]=0x00;
	mod_sources_params[2]=0x0B;//Pitch Mod 2 Src
	mod_sources_params[3]=0x02;
	mod_sources_params[4]=0x05;//Amp mod src
	mod_sources_params[5]=0x09;
	mod_sources_params[6]=0x05;//Filter mod input 1
	mod_sources_params[7]=0x09;
	mod_sources_params[8]=0x08;//Filter mod input 2
	mod_sources_params[9]=0x09;
	mod_sources_params[10]=0x09;//Filter mod input 3
	outputfile->writeBlock(mod_sources_params.data(),mod_sources_params.size());
//<-009D
//end Keygroup Mod Sources

	//keygroup start
	if(nb_keygroups==0){
		writeKeygroup(outputfile,NULL,1); //emtpy program
	}
	for (int i=0;i<nb_keygroups;i++){
		writeKeygroup(outputfile,filenames->operator[](i),i);
	}
	//keygroup end
}


void AKPManager::writeZone(QFile* file,QString filename){
        file->writeBlock("zone",4);
        write4Bytes(file,0x2E);
        writeByte(file,0x01);
        QByteArray samplename=getPaddedSampleName(filename);
        writeByte(file,filename.length());
        file->writeBlock(samplename.data(),samplename.size());
        QByteArray zero_12(12);
        zero_12.fill(0x00);
        file->writeBlock(zero_12.data(),zero_12.size());
        QByteArray params(12);
        params[0]=0x00; //Low Velocity
        params[1]=0x7F;//High Velocity
        params[2]=0x00;// Fine tune
        params[3]=0x00;// Semitone tune
        params[4]=0x00;//Filter
        params[5]=0x00;//Pan/Balance
        params[6]=0x00;//Playback 0 = NO LOOPING, 1 = ONE SHOT, 2 = LOOP IN REL,3 = LOOP UNTIL REL, 4 = AS SAMPLE
        params[7]=0x00;//Output
        params[8]=0x00;//Zone Level
        params[9]=0x00;//Keyboard Track (0=OFF, 1=ON)
        params[10]=0x00;//Velocity->Start LSB
        params[11]=0x00;//Velocity->Start MSB
        file->writeBlock(params.data(),params.size());
}

void AKPManager::writeKeygroup(QFile* file,QString filename,int i){
	//009E->
        file->writeBlock("kgrp",4);
        write4Bytes(file,0x50,0x01);
        file->writeBlock("kloc",4);
        write4Bytes(file,0x10);
        QByteArray kloc_params(16);
        kloc_params[0]=0x01;
        kloc_params[1]=0x03;
        kloc_params[2]=0x01;
        kloc_params[3]=0x04;
        kloc_params[4]=i+36; //low note (start at C1 )
        kloc_params[5]=i+36; //high_note (end at C1)
        kloc_params[6]=0x00;//seminote tune
        kloc_params[7]=0x00;//fine tune
        kloc_params[8]=0x00;//overide fx
        kloc_params[9]=0x00;//FX send Level
        kloc_params[10]=0x64;//pitch mod 1
        kloc_params[11]=0x00;//pitch mod 2
        kloc_params[12]=0x00;//amp mod
        kloc_params[13]=0x00;//zone XFade
        kloc_params[14]=0x00;//mute group
        kloc_params[15]=0x00;
        file->writeBlock(kloc_params.data(),kloc_params.size());

        file->writeBlock("env ",4); //amp env
        write4Bytes(file,0x12);
        QByteArray amp_env_params(18);
        amp_env_params[0]=0x01;
        amp_env_params[1]=0x00; //attack
        amp_env_params[2]=0x00;
        amp_env_params[3]=0x32; //decay
        amp_env_params[4]=0x0F; //release
        amp_env_params[5]=0x00;
        amp_env_params[6]=0x00;
        amp_env_params[7]=0x64;//sustain
        amp_env_params[8]=0x00;
        amp_env_params[9]=0x00;
        amp_env_params[10]=0x00; //Velo->Attack
        amp_env_params[11]=0x00;
        amp_env_params[12]=0x00;//Keyscale
        amp_env_params[13]=0x00;
        amp_env_params[14]=0x00;//On Vel->Rel
        amp_env_params[15]=0x00;//Off Vel->Rel
        amp_env_params[16]=0x00;
        amp_env_params[17]=0x00;//
        file->writeBlock(amp_env_params.data(),amp_env_params.size());
        //<-00D7
        //00D8->
        file->writeBlock("env ",4); //filter env
        write4Bytes(file,0x12);
        QByteArray filt_env_params(18);
        filt_env_params[0]=0x01;
        filt_env_params[1]=0x00; //attack
        filt_env_params[2]=0x00;
        filt_env_params[3]=0x32; //decay
        filt_env_params[4]=0x0F; //release
        filt_env_params[5]=0x00;
        filt_env_params[6]=0x00;
        filt_env_params[7]=0x64;//sustain
        filt_env_params[8]=0x00;
        filt_env_params[9]=0x00; //Filt env dept
        filt_env_params[10]=0x00; //Velo->Attack
        filt_env_params[11]=0x00;
        filt_env_params[12]=0x00;//Keyscale
        filt_env_params[13]=0x00;
        filt_env_params[14]=0x00;//On Vel->Rel
        filt_env_params[15]=0x00;//Off Vel->Rel
        filt_env_params[16]=0x00;
        filt_env_params[17]=0x00;//
        file->writeBlock(filt_env_params.data(),filt_env_params.size());
        //<-00F1
        //00F2->
        file->writeBlock("env ",4); //aux env
        write4Bytes(file,0x12);

        QByteArray aux_env_params(18);
        aux_env_params[0]=0x01;
        aux_env_params[1]=0x00; //rate 1
        aux_env_params[2]=0x32; //rate 2
        aux_env_params[3]=0x32; //rate 3
        aux_env_params[4]=0x0F; //rate 4
        aux_env_params[5]=0x64; //level 1
        aux_env_params[6]=0x64; //level 2
        aux_env_params[7]=0x64; //level 3
        aux_env_params[8]=0x00; //level 4
        aux_env_params[9]=0x00;
        aux_env_params[10]=0x00; //Vel->Rate1
        aux_env_params[11]=0x00;
        aux_env_params[12]=0x00; //Keyboard->R2/R4
        aux_env_params[13]=0x00;
        aux_env_params[14]=0x00;//Vel->Rate 4
        aux_env_params[15]=0x00;//Off Vel->Rate 4
        aux_env_params[16]=0x00;//Vel->Out Level
        aux_env_params[17]=0x85;
        file->writeBlock(aux_env_params.data(),aux_env_params.size());
        //<-010B
        //010C->
        file->writeBlock("filt",4);
        write4Bytes(file,0x0A);
        QByteArray filt_params(10);
        filt_params[0]=0x01;
        filt_params[1]=0x00;//Filter Mode
        filt_params[2]=0x64;//Cutoff Freq
        filt_params[3]=0x00;//Resonance
        filt_params[4]=0x00;//Keyboard Track
        filt_params[5]=0x00;//Mod Input 1
        filt_params[6]=0x00;//Mod Input 2
        filt_params[7]=0x00;//Mod Input 3
        filt_params[8]=0x00;//Headroom
        filt_params[9]=0x00;
        file->writeBlock(filt_params.data(),filt_params.size());
        //<-011D
        //Zone 1
        writeZone(file,filename);
        //<-0153
        //end zone 1
        //0154->
        writeZone(file,NULL); //zone 2
        writeZone(file,NULL); //zone 3
        writeZone(file,NULL); //zone 4
        //<-01FP
}

QByteArray AKPManager::getPaddedSampleName(QString filename){
        QByteArray name(20);
	name.fill(0x00);
	if(filename){
                 filename=filename.replace( ".wav", "",FALSE );
		for (int i=0;i<filename.length();i++){
			name[i]=(QChar)filename.at(i);
		}
	}
         return name;
}

void AKPManager::write4Bytes(QFile* file,char fst,char snd,char trd,char fth){
    QByteArray data(4);
    data[0]=fst;
    data[1]=snd;
    data[2]=trd;
    data[3]=fth;
    file->writeBlock(data.data(),data.size());
}

void AKPManager::writeByte(QFile* file,char fst){
    file->writeBlock(&fst,1);
}


