/***************************************************************************
 * guitarpro4.h: implementation of GuitarPro4 class
 *
 * This file is part of KTabEdit, a KDE tabulature editor
 *
 * copyright (C) 2003-2006 the KTabEdit development team <mrgwen@gmail.com>
 * copyright (C) 2002-2003 the KGuitar development team <mrgwen@gmail.com>
 ***************************************************************************/

/***************************************************************************
 * 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.
 *
 * See the file COPYING for more information.
 ***************************************************************************/

#include "guitarpro4.h"

#include "util/assert.h"
#include "util/logger.h"

#include "tablature/tabbeateffects.h"
#include "tablature/tabchord.h"
#include "tablature/tabduration.h"

#include "tablature/tabbend.h"
#include "tablature/tabdynamic.h"

#include "tablature/tabgracenotetransition.h"
#include "tablature/tabgracenote.h"

#include "tablature/tabharmonic.h"
#include "tablature/tabslide.h"
#include "tablature/tabtrill.h"
#include "tablature/tabnoteeffect.h"

#include "tablature/tabnote.h"

#include "tablature/songkey.h"
#include "tablature/timesignature.h"

#include "tablature/tabmixtablechanges.h"
#include "tablature/tabtimes.h"
#include "tablature/tabbarproperties.h"

#include "tablature/tabbar.h"

#include "tablature/tablyrics.h"
#include "tablature/tabproperties.h"

#include "tablature/tabsong.h"

#include "tablature/trackmidiproperties.h"
#include "tablature/trackproperties.h"

#include "tablature/tabtrack.h"

GuitarPro4::GuitarPro4()
: mInstruments(64),
  mTrackProperties(0)
{
}

GuitarPro4::~GuitarPro4()
{
	for (uint i = 0; i < 64; i++)
		delete mInstruments.at(i);
}

void GuitarPro4::dummies(uint i)
{
	for (uint k = 0; k < i; k++) {
		mFile.getch();
		
		if (mFile.atEnd())
			throw "End of file";
	}
}
unsigned char GuitarPro4::getByte()
{
	int result = mFile.getch();
	
	if (result == -1)
		throw "End of file";
	
	return result;
}

unsigned long GuitarPro4::getLong()
{
	unsigned long i = getByte() | getByte() << 8 | getByte() << 16 | getByte() << 24;
	
	return i;
}

QString GuitarPro4::getString()
{
	char* readBlock;
	int result = 0;
	int max = getLong();
	QString temp;
	
	if (max > 0) {
		int i = getByte();
		
		if (i != max - 1)
			throw "Wrong string length";
		
		
		readBlock = new char[i + 1];
		result = mFile.readBlock(readBlock, i);
		
		if (result == -1 || (result == 0 && i != 0))
			throw "End of file";
		
		temp = QString::fromLocal8Bit(readBlock, i);
		
		delete[] readBlock;
	} else {
		max = getByte();
	}
	
	return temp;
}

QString GuitarPro4::getStringNoInc(int i)
{
	char* readBlock;
	int result = 0;
	int nb = getByte();
	QString temp;
	
	readBlock = new char[nb + 1];
	result = mFile.readBlock(readBlock, nb);
	
	if (result == -1 || (result == 0 && nb != 0))
		throw "End of file";
	
	temp = QString::fromLocal8Bit(readBlock, nb);
	
	//ktabedit::ktabLog << "getStringNoInc " << i << " " << nb << " |" << temp << "|\n";
	
	delete[] readBlock;
	
	if (i)
		dummies(i - nb);
	
	return temp;
}

QString GuitarPro4::getDelphiString()
{
	char* readBlock;
	int result = 0;
	unsigned long max = getLong();
	QString temp;
	
	readBlock = new char[max + 1];
	result = mFile.readBlock(readBlock, max);
	
	if (result == -1 || (result == 0 && max != 0))
		throw "End of file";
	
	temp = QString::fromLocal8Bit(readBlock, max);
	
	//ktabedit::ktabLog << "getDelphiString " << max << " |" << temp << "|\n";
	
	delete[] readBlock;
	
	return temp;
}

QString GuitarPro4::getChordName()
{
	int result;
	char* readBlock;
	QString temp;
	unsigned int max = 20;
	
	readBlock = new char[22];
	result = mFile.readBlock(readBlock, 21);
	
	if (result == -1)
		throw "End of file";
	
	temp = QString::fromLocal8Bit(readBlock, 21);
	
	delete[] readBlock;
	
	if (temp[0] < max) {
		max = temp[0].latin1();
	}
	
	for(uint i = 1; i <= max ; i++) {
		temp[i-1] = temp[i] ;
	}
	
	temp[max] = 0;
	
	return temp;
}

unsigned char GuitarPro4::getBeatDuration()
{
	unsigned char beatDuration = getByte();
	
	if (beatDuration > 128)
		beatDuration-=256;
	
	return beatDuration;
}

// This code is traducted from the python code of songwrite
//
bool GuitarPro4::loadFile(const QString &fileName)
{
	TabSong::iterator it;
	unsigned char command, beatduration;
	unsigned int i, j, k, noteVolume, nbbeats, noteLength;
	bool rest = false;
	TabSong* tabSong = new TabSong();
	TabChord tabChord;
	TabBar* bar;
	TabTime* time;
	
	// Open file
	//
	mFile.setName(fileName);
	
	if (!mFile.open(IO_ReadOnly)) {
		//ktabedit::ktabLog << "Cannot open file" << "\n";
		throw "Cannot open file";
	}
	
	readHeader(tabSong);
	
	readMidi();
	
	readBars(tabSong);
	
	readTracks(tabSong);
	
	i = 0;
	while (i < mNbbars) {
		j = 0;
	
		//ktabedit::ktabLog << "Lecture de la mesure " << i << "/" << mNbbars << "\n" << "\n";
		
		it = tabSong->begin();
		
		while (j < mNbtrack) {
			noteVolume = 0xCC;
			
			nbbeats = getLong();
			
			//ktabedit::ktabLog << "Analyse de la piste " << j << " (" << nbbeats << " nombre de notes)" << "\n" << "\n";
			
			TabTrack& tabTrack = **it;
			++it;
			
			bar = new TabBar(i, 4, 4);
			TabBarProperties* properties = new TabBarProperties();
			properties->clone(mTrackProperties[i]);
			bar->setProperties(properties);
			
			k = 0;
			
			while (k < nbbeats) {
				time = new TabTime(k);
				noteLength = 0;
				rest = false;
				
// 				notes.setNbFrets(track->getNbFrets());
				
				command = getByte();
				
				//ktabedit::ktabLog << k << " Commande = " << static_cast<int>(command) << "\n";
				
				if (command & 0x40) {
					// Beat status
					getByte();
					// If byte == 0x00 empty
					// If byte == 0x02 rest
					//ktabedit::ktabLog << "REST found " <<  noteLength << "\n";
					rest = true;
				}
				
				if (command & 0x01) {
					//ktabedit::ktabLog << "Dotted time" << "\n";
					time->setDotted(true);
				}
				
				beatduration = getBeatDuration();
				
				if (command & 0x20) {
					time->setNTuplet(getLong() - 1);
					//ktabedit::ktabLog << "NTuplet " << notes.nTuplet() << "\n";
				}
				
				if (command & 0x02) {
					//ktabedit::ktabLog << "Accord\n";
					time->setTabChord(readChords());
					time->setChord(true);
				}
				
				if (command & 0x04) {
					time->setText(getString());
					//ktabedit::ktabLog << "Text found " << notes.text() << "\n";
				}
				
				if (command & 0x08) {
					readEffectsOnBeat(time->effect());
				}
				
				if (command & 0x10) {
					readChanges(bar->mixer());
				}
				
				readNotes(rest, beatduration, time, noteLength);
				
				bar->insertTime(time);
				
				k++;
			}
			j++;
			
			tabTrack.addBar(bar);
		}
		i++;
	}
	
	mFile.close();
	
	setTabSong(tabSong);
	
	for (int i = 0; i < mTrackProperties.size(); i++)
		delete mTrackProperties[i];
	
	return true;
}

void GuitarPro4::readHeader(TabSong* tabSong)
{
	// Check file signature
	//
	const QString gtpId4a("FICHIER GUITAR PRO v4.00");
	const QString gtpId4b("FICHIER GUITAR PRO v4.06");
	int i;
	long noticeNbLines;
	QString header;
	QString notice;
	
	if ((header = getStringNoInc(30)) != gtpId4a && header != gtpId4b) {
		mFile.close();
		//ktabedit::ktabLog << "The header is not correct : " << header << ".\nThe header must be : " << gtpId4a << ".\n" 
		//		<< "Or : " << gtpId4b << ".\n";
		throw "Not a Guitar Pro file!";
	}
	
	tabSong->setTitle(getString());
	//ktabedit::ktabLog << "Title = " << tabSong->title() << "\n";
	
	tabSong->setSubTitle(getString());
	//ktabedit::ktabLog << "Subtitle = " << tabSong->subTitle() << "\n";

	tabSong->setArtist(getString());
	//ktabedit::ktabLog << "Artist = " << tabSong->artist() << "\n";

	tabSong->setAlbum(getString());
	//ktabedit::ktabLog << "Album = " << tabSong->album() << "\n";

	tabSong->setAuthor(getString());
	//ktabedit::ktabLog << "Author = " << tabSong->author() << "\n";

	tabSong->setCopyright(getString());
	//ktabedit::ktabLog << "Copyright = " << tabSong->copyright() << "\n";

	tabSong->setTranscriber(getString());
	//ktabedit::ktabLog << "Transcriber = " << tabSong->transcriber() << "\n";

	tabSong->setInstructions(getString());
	//ktabedit::ktabLog << "Instruction = " << tabSong->instructions() << "\n";

	noticeNbLines = getLong();
	//ktabedit::ktabLog << "Nombre de lignes des commentaires :" << noticeNbLines << "\n";
	
	i = 0;
	while (i < noticeNbLines) {
		notice+=getString();
		notice+='\n';
		i++;
	}
	tabSong->setComments(notice);
	//ktabedit::ktabLog << "Commentaires =" << notice << "\n";
	
	tabSong->setShuffle(static_cast<bool>(getByte()));
	//ktabedit::ktabLog << "Shuffle =" << tabSong->isShuffle() << "\n";
	
	tabSong->setLyricsTrack(getLong());
	//ktabedit::ktabLog << "lyricsTrack = " << tabSong->lyricsTrack() << "\n";
	for (i = 0; i < 5; i++) {
		tabSong->setLyricsMeasure(i, getLong());
		tabSong->setLyrics(i, getDelphiString());
		
		//ktabedit::ktabLog << "paroles = " << tabSong->lyricsMeasure(i) << "\n";
		//ktabedit::ktabLog << "paroles = " << tabSong->lyrics(i) << "\n";
	}
	
	tabSong->setTempo(getLong());
	//ktabedit::ktabLog << "Tempo =" << tabSong->tempo() << "\n";
	
	tabSong->setKey(getByte());
	//ktabedit::ktabLog << "Key =" << tabSong->nameOfKey() << "\n";
	
	tabSong->setOctave(getLong());
	//ktabedit::ktabLog << "octave =" << tabSong->octave() << "\n";
}

void GuitarPro4::readMidi()
{
	// Lecture des instruments
	//
	uchar i = 0;
	
	//ktabedit::ktabLog << "Lecture des instruments =" << "\n";
	while (i < 64) {
		mInstruments[i] = new TrackMidiProperties();
		mInstruments[i]->setPatch(getLong());
		mInstruments[i]->setVolume(getByte());
		mInstruments[i]->setBalance(getByte());
		mInstruments[i]->setChorus(getByte());
		mInstruments[i]->setReverb(getByte());
		mInstruments[i]->setPhaser(getByte());
		mInstruments[i]->setTremolo(getByte());
		
		//ktabedit::ktabLog << "Instrument n " << (int)i << " " << mInstruments[i].patch() << " Volume " << (int)mInstruments[i].volume() 
		//<< " balance " << (int)mInstruments[i].balance() << " chorus " << (int)mInstruments[i].chorus() << " reverb " << (int) mInstruments[i].reverb() 
		//<< " phaser " << (int)mInstruments[i].phaser() << " tremolo " << (int)mInstruments[i].tremolo() << "\n";
		 
		dummies(2);
		i++;
	}
}

void GuitarPro4::readBars(TabSong* tabSong)
{
	unsigned int i;
	
	mNbbars = getLong();
	//ktabedit::ktabLog << "\n\n" << "Nombre de mesures =" << mNbbars << "\n";
	
	mNbtrack = getLong();
	//ktabedit::ktabLog << "Nombre de pistes =" << mNbtrack << "\n";
	
	// Read track infos: name
	//
	tabSong->clear();
	
	mTrackProperties.resize(mNbbars);
	
	unsigned char barFlag;
	unsigned char barRythm1 = 4, barRythm2 = 4;
	
	i = 0;
	while (i < mNbbars) {
		barFlag = getByte();
		
		//ktabedit::ktabLog << "Mesure =" << i << "\n";
		
		if (barFlag & 1) {
			barRythm1 = getByte();
			//ktabedit::ktabLog << "Bar rythm 1 =" << static_cast<int>(barRythm1) << "\n";
		}
		
		if (barFlag & 2) {
			barRythm2 = getByte();
			//ktabedit::ktabLog << "Bar rythm 2 =" << static_cast<int>(barRythm2) << "\n";
		}
		
		mTrackProperties[i] = new TabBarProperties();
		mTrackProperties[i]->setNumerator(barRythm1);
		mTrackProperties[i]->setDenominator(barRythm2);
		
		if (barFlag & 4) {
			//ktabedit::ktabLog << "Open repeat barFlag & 4" << "\n";
			mTrackProperties[i]->setRepeatStart(true);
		}
		
		if (barFlag & 8) {
			//ktabedit::ktabLog << "Repeat close barFlag & 8" << "\n";
			mTrackProperties[i]->setRepetitions(getByte());
		}
		
		if (barFlag & 0x10) {
			//ktabedit::ktabLog << "Open alt barFlag & 16" << "\n";
			mTrackProperties[i]->setAlternateEndings(getByte());
		}
		
		if (barFlag & 0x20) {
			//ktabedit::ktabLog << "Marker barFlag & 32" << "\n";
			QString marker(getString());
			QColor color(getByte(), getByte(), getByte());
			
			//ktabedit::ktabLog << "Marker =" << marker << "Couleur r :" << color << "\n";
			
			// Empty byte
			//
			getByte();
			
			mTrackProperties[i]->setMarker(marker);
			mTrackProperties[i]->setColor(color);
		}
		
		if (barFlag & 0x40) {
			//ktabedit::ktabLog << "Armor change barFlag & 64" << "\n";
			// Armor jump
			//
			mTrackProperties[i]->setKey(getByte());
			// Minor
			//
			mTrackProperties[i]->setMinor(getByte());
			
			//ktabedit::ktabLog << "Key =" << mTrackProperties[i]->nameOfKey() << "\n";
			
			//ktabedit::ktabLog << "Key =" << mTrackProperties[i]->isMinor() << "\n";
		}
		
		if (barFlag & 0x80) {
			//ktabedit::ktabLog << "Double bar barFlag & 0x80" << "\n";
			mTrackProperties[i]->setDoubleBar(true);
		}
		
		i++;
	}
}

void GuitarPro4::readTracks(TabSong* tabSong)
{
	unsigned int i = 0;
	unsigned long tunning[7];
	
	//ktabedit::ktabLog << "Track" << "\n";
	
	while (i < mNbtrack) {
		TrackMode mode = FretTab;
		
		unsigned char header = getByte();
		
		if (header & 1) {
			//ktabedit::ktabLog << "drum track" << "\n";
			mode = DrumTab;
		}
		
		if (header & 2) {
			//ktabedit::ktabLog << "12 strings track" << "\n";
			mode = TwelveStringsTab;
		}
		
		if (header & 4) {
			//ktabedit::ktabLog << "banjo track" << "\n";
			mode = BanjoTab;
		}
		
		QString trackName = getStringNoInc(40);
		//ktabedit::ktabLog << "Track Name =" << track << "\n";
		
		long nbStrings = getLong();
		//ktabedit::ktabLog << "Nb Strings =" << nbStrings << "\n";
		
		if (mode == DrumTab)
			nbStrings = 4;
		
		//ktabedit::ktabLog << "Tuning =\n";
		
		int j = 0;
		while (j < 7) {
			tunning[j] = getLong();
			j++;
		}
		
		int midiPort = getLong();
		//ktabedit::ktabLog << "Midi port =" << midiPort << "\n";
		
		int channel = getLong();
		//ktabedit::ktabLog << "Channel 1 =" << channel << "\n";
		
		int channelEffects = getLong();
		//ktabedit::ktabLog << "Channel effects =" << channelEffects << "\n";
		
		int nbFrets = getLong();
		//ktabedit::ktabLog << "Nb frets =" << nbFrets << "\n";
		
		int capo = getLong();
		//ktabedit::ktabLog << "Capo =" << capo << "\n";
		
		QColor color(getByte(), getByte(), getByte());
		//ktabedit::ktabLog << "Color =" << "Couleur :" << color << "\n";
		
		// Empty byte
		//
		getByte();
		
		TabTrack* track = new TabTrack(mode, trackName, 0, 0, mInstruments[channel]->patch(), nbStrings, nbFrets);
		TrackMidiProperties* midi = new TrackMidiProperties();
		
		for (j = 0; j < nbStrings; j++)
			track->setTune(nbStrings - 1 - j, tunning[j]);
		
		midi->clone(mInstruments[channel]);
		track->setMidiProperties(midi);
		track->setCapo(capo);
		track->setColor(color);
		track->setChannel(channel);
		track->setChannelEffects(channelEffects);
		track->setMidiPort(midiPort);
		
		tabSong->push_front(track);
		
		i++;
	}
}

void GuitarPro4::readEffectsOnBeat(TabTimeEffect* timeEffect)
{
	uchar command = getByte();
	uchar command2 = getByte();
	//ktabedit::ktabLog << "Beat effect " << (int)command << "\n";
	
	if (command & 0x20) {
		uchar effect = getByte();
		
		if (!effect) {
			//ktabedit::ktabLog << "Tremolo bar" << "\n";
			unsigned int value = getLong();
			
			timeEffect->setTremolo(value);
		} else {
			switch(effect) {
				case 1:
					//ktabedit::ktabLog << "Tapping\n";
					
					timeEffect->setTapping(true);
					break;
				case 2:
					//ktabedit::ktabLog << "slapping\n";
					
					timeEffect->setSlapping(true);
					break;
				case 3:
					//ktabedit::ktabLog << "Popping\n";
					
					timeEffect->setPopping(true);
					break;
// 				default:
// 					throw "Unexpected value in effect";
			}
		}
	}
	
	if (command2 & 0x04) {
		//ktabedit::ktabLog << "Note effect : Bend" << "\n";
			
		// Type of the bend
		//
		timeEffect->setBendType(static_cast<TabBend::BendType>(getByte()));
		
		//Vertical height
		//
		timeEffect->setBendValue(getLong());
		
		// num points
		//
		int numPoints = getLong();
		
		TabBendPoint* point;
		
		for (int i = 0; i < numPoints; i++) {
			point = new TabBendPoint();
			
			point->setPosition(getLong());
			point->setHeight(getLong());
			point->setVibrato(static_cast<TabVibrato>(getByte()));
			
			timeEffect->addBendPoint(point);
		}
	}
	
	if (command & 0x40) {
		//ktabedit::ktabLog << "Strocke" << "\n";
		
		timeEffect->setStroke(true);
		
		int duration = getByte();
		//ktabedit::ktabLog << "duration " << duration << "\n";
		if (duration)
			timeEffect->setUpStroke(6 - duration);
		
		duration = getByte();
		//ktabedit::ktabLog << "duration " << duration << "\n";
		if (duration)
			timeEffect->setDownStroke(6 - duration);
	}
	
	if (command2 & 0x01) {
		// Rasgueado
		//
		//ktabedit::ktabLog << "rasgueado\n";
		timeEffect->setRasgueado(true);
	}
	
	if (command2 & 0x02) {
		// Pickstroke
		//ktabedit::ktabLog << "pickstroke\n";
		timeEffect->setPickStroke(static_cast<PickStroke>(getByte()));
	}
	
	if (command & 0x01) {
		timeEffect->setVibrato(true);
		//ktabedit::ktabLog << "Vibrato" << "\n";
	}
	
	if (command & 0x02) {
		timeEffect->setWideVibrato(true);
		//ktabedit::ktabLog << "Wide vibrato" << "\n";
	}
	
	if (command & 0x04) {
		timeEffect->setNaturalHarmonic(true);
		//ktabedit::ktabLog << "Natural harmonic" << "\n";
	}
	
	if (command & 0x08) {
		timeEffect->setArtificialHarmonic(true);
		//ktabedit::ktabLog << "Other harmonic" << "\n";
	}
	
	if (command & 0x10) {
		timeEffect->setFadeIn(true);
		//ktabedit::ktabLog << "Fade in" << "\n";
	}
}

void GuitarPro4::readEffectsOnNote(TabNoteEffect* noteEffect)
{
	//ktabedit::ktabLog << " Special note\n";
	uchar effect_1 = getByte();
	uchar effect_2 = getByte();
	
	//ktabedit::ktabLog << " Effect 1 =" << (int)effect_1 << "\n";
	//ktabedit::ktabLog << " Effect 2 =" << (int)effect_2 << "\n";
	
	if (effect_1 & 0x01) {
		//ktabedit::ktabLog << "Note effect : Bend" << "\n";
		
		// Absolute time position
		//
		noteEffect->setBendType(static_cast<TabBend::BendType>(getByte()));
		
		//Vertical height
		//
		noteEffect->setBendValue(getLong());
		
		//ktabedit::ktabLog << "bendValue = " << noteEffect->bendValue() << "\n";
		
		// num points
		//
		int numPoints = getLong();
		
		TabBendPoint* point;
		
		for (int i = 0; i <numPoints; i++) {
			point = new TabBendPoint();
			
			point->setPosition(getLong());
			//ktabedit::ktabLog << "bendPosition = " << point.position() << "\n";
			point->setHeight(getLong());
			//ktabedit::ktabLog << "bendHeight = " << point.height() << "\n";
			point->setVibrato(static_cast<TabVibrato>(getByte()));
			//ktabedit::ktabLog << "bendVibrato = " << point.tabVibrato() << "\n";
			
			noteEffect->addBendPoint(point);
		}
	}
	
	
	if (effect_1 & 0x04) {
		//ktabedit::ktabLog << "Note effect : Slide" << "\n";
		noteEffect->setSlide(ShiftSlide);
	}
	
	if (effect_1 & 0x10) {
		//ktabedit::ktabLog << "Note effect : Grace note" << "\n";
		// Fret
		noteEffect->setGraceNoteFret(getByte());
		// Dynamic
		noteEffect->setGraceNoteDynamic(static_cast<Dynamic>(getByte()));
		// Transition
		noteEffect->setGraceNoteTransition(static_cast<GraceNoteTransition>(getByte()));
		// Duration
		noteEffect->setGraceNoteDuration(getByte());
	}
	
	if (effect_2 & 0x04) {
		//ktabedit::ktabLog << "tremolo picking\n";
		noteEffect->setTremoloPicking(getByte());
	}
	
	if (effect_2 & 0x08) {
		//ktabedit::ktabLog << "Note effect : Slide" << "\n";
		noteEffect->setSlide(static_cast<Slide>(getByte()));
	}
	
	if (effect_2 & 0x10) {
		// Harmonic
		//
		noteEffect->setHarmonic(static_cast<Harmonic>(getByte()));
	}
	
	if (effect_2 & 0x20) {
		// Trill
		//
		//ktabedit::ktabLog << "Note effect : Trill" << "\n";
		
		// Fret
		//
		noteEffect->setFretTrill(getByte());
		
		// Duration
		//
		noteEffect->setPeriod(getByte());
	}
	
	if (effect_1 & 0x08) {
		//ktabedit::ktabLog << "Note effect : Let Ring" << "\n";
		noteEffect->setLetRing(true);
	}
	
	if (effect_1 & 0x02) {
		//ktabedit::ktabLog << "Note effect : Pull" << "\n";
		noteEffect->setHammerOnPullOff(true);
	}
	
	if (effect_2 & 0x40) {
		// Left hand vibrato
		noteEffect->setLeftHandVibrato(true);
	}
	
	if (effect_2 & 0x02) {
		// Palm mute
		noteEffect->setPalmMute(true);
	}
	
	if (effect_2 & 0x01) {
		// Staccato
		noteEffect->setStaccato(true);
	}
}

void GuitarPro4::readChanges(TabMixTableChanges* mixer)
{
	//ktabedit::ktabLog << "Change" << "\n";
	
	uchar new_inst = getByte();
// 	//ktabedit::ktabLog << "Instrument " << static_cast<int>(new_inst) << "\n";
	
	uchar new_vol = getByte();
// 	//ktabedit::ktabLog << "Volume " << static_cast<int>(new_vol) << "\n";
	
	uchar new_pan = getByte();
// 	//ktabedit::ktabLog << "Pan " << static_cast<int>(new_pan) << "\n";
	
	uchar new_chorus = getByte();
// 	//ktabedit::ktabLog << "Chorus " << static_cast<int>(new_chorus) << "\n";
	
	uchar new_reverb = getByte();
// 	//ktabedit::ktabLog << "Reverb " << static_cast<int>(new_reverb) << "\n";
	
	uchar new_phaser = getByte();
// 	//ktabedit::ktabLog << "Phaser " << static_cast<int>(new_phaser) << "\n";
	
	uchar new_tremolo = getByte();
// 	//ktabedit::ktabLog << "Tremolo " << static_cast<int>(new_tremolo) << "\n";
	
	int new_tempo = getLong();
// 	//ktabedit::ktabLog << "Tempo " << static_cast<int>(new_tempo) << "\n";
	
	if (new_vol != 255) {
		mixer->setInstrument(new_inst);
		dummies(1);
	}
	
	if (new_pan != 255) {
		mixer->setBalance(new_pan);
		dummies(1);
	}
	
	if (new_chorus != 255) {
		mixer->setChorus(new_chorus);
		dummies(1);
	}
	
	if (new_reverb != 255) {
		mixer->setReverb(new_reverb);
		dummies(1);
	}
	
	if (new_phaser != 255) {
		mixer->setPhaser(new_phaser);
		dummies(1);
	}
	
	if (new_tremolo != 255) {
		mixer->setTremolo(new_tremolo);
		dummies(1);
	}
	
	if (new_tempo != -1) {
		mixer->setTempo(new_tempo);
		dummies(1);
	}

// 	if (new_vol != 255) dummies(1);
// 	if (new_pan != 255) dummies(1);
// 	if (new_chorus != 255) dummies(1);
// 	if (new_reverb != 255) dummies(1);
// 	if (new_phaser != 255) dummies(1);
// 	if (new_tremolo != 255) dummies(1);
// 	if (new_tempo != -1) dummies(1);
	
	// Apply to all
	//
	getByte();
}

TabChord* GuitarPro4::readChords()
{
	uchar header = getByte();
	TabChord* chord = new TabChord();
	
	if ((header & 0x01) == 0) {
		chord->setName(getString());
		
		int base = getLong();
		
		chord->setBaseFret(base);
		
		if (base != 0) {
			for (int i = 0; i < 6; i++) {
				chord->setFret(i, getLong());
			}
		}
	} else {
		
		
		// Sharp
		//
		chord->setSharp(getByte());
		//ktabedit::ktabLog << "sharp = " << chord->isSharp() << "\n";
		
		// Skip 3 bytes
		//
		dummies(3);
		
		// GP4Root
		//
		chord->setRoot(getByte());
		//ktabedit::ktabLog << "root = " << chord->root() << "\n";
		
		// Chord type
		//
		chord->setType(getByte());
		//ktabedit::ktabLog << "type = " << chord->type() << "\n";
		
		// 9, 11, 13
		//
		chord->setNineElevenThirteen(static_cast<TabChord::ExtentionChord>(getByte()));
		
		//ktabedit::ktabLog << "9, 11, 13 = " << chord->nineElevenThirteen() << "\n";
		
		// Bass
		//
		chord->setBass(getLong());
		//ktabedit::ktabLog << "bass = " << chord->bass() << "\n";
		
		// Augmented or diminished
		//
		chord->setAugmentedDiminished(static_cast<TabChord::AugmentedDiminished>(getLong()));
		//ktabedit::ktabLog << "+ - = " << chord->augmentedDiminished() << "\n";
		
		// Added Note
		//
		chord->setAddedNote(getByte());
		//ktabedit::ktabLog << "added note = " << chord->addedNote() << "\n";
		
		// Name
		//
		chord->setName(getChordName());
		//ktabedit::ktabLog << "chord name = " << chord->name() << "\n";
		
		// Skip 2 bytes
		//
		dummies(2);
		
		// Tonality five
		//
		chord->setTonalityFive(getByte());
		//ktabedit::ktabLog << "tonality five = " << chord->tonalityFive() << "\n";
		
		// Tonality nine
		//
		chord->setTonalityNine(getByte());
		//ktabedit::ktabLog << "tonality nine = " << chord->tonalityNine() << "\n";
		
		// Tonality eleven
		//
		chord->setTonalityEleven(getByte());
		//ktabedit::ktabLog << "tonality eleven = " << chord->tonalityEleven() << "\n";
		
		// Base fret
		//
		chord->setBaseFret(getLong());
		//ktabedit::ktabLog << "base fret = " << chord->baseFret() << "\n";
		
		// Reads the 6 frets
		//
		for (int i = 0; i < 7; i++) {
			chord->setFret(i, getLong());
			//ktabedit::ktabLog << "fret = " << chord->fret(i) << "\n";
		}
		
		// Num barres
		//
		chord->setNumBarres(getByte());
		//ktabedit::ktabLog << "num barres = " << chord->numBarres() << "\n";
		
		// Fret of barre
		//
		for (int i = 0; i < 5; i++) {
			chord->setBarreFret(i, getByte());
			//ktabedit::ktabLog << "fret of barre = " << chord->barreFret(i) << "\n";
		}
		
		// Barre start
		//
		for (int i = 0; i < 5; i++) {
			chord->setBarreStart(i, getByte());
			//ktabedit::ktabLog << "bare start = " << chord->barreStart(i) << "\n";
		}
		
		// Barre end
		//
		for (int i = 0; i < 5; i++) {
			chord->setBarreEnd(i, getByte());
			//ktabedit::ktabLog << "bare end = " << chord->barreEnd(i) << "\n";
		}
		
		dummies(8);
		
		// Omission : gives the notes present in the chord
		for (int i = 0; i < 7; i++) {
			chord->setFingering(i, getByte());
			//ktabedit::ktabLog << " " << chord->fingering(i) << "\n";
		}
		
		
		// Show diagram
		//
		chord->setShowDiagram(getByte());
	}
	
	return chord;
}

void GuitarPro4::readNotes(bool rest, uchar beatduration, TabTime* time, uint noteLength)
{
	char strings_fill = getByte(), numberOfStrings = 0, i;
	TabNote* note;
	
	if (rest) {
		switch(beatduration) {
		case 0:
			time->setDuration(Quarter);
			break;
		case 1:
			time->setDuration(Eighth);
			break;
		case 2:
			time->setDuration(Sixteenth);
			break;
		case 3:
			time->setDuration(ThirthSecond);
			break;
		case 4:
			// Quadruple croche
			time->setDuration(SixtyFourth);
			break;
		case 0xff:
			time->setDuration(Half);
			break;
		case 0xfe:
			time->setDuration(Whole);
			break;
		}
		
		time->setRest(true);
		
		rest = false;
	}
	
	for (i = 0; i < 7; i++) {
		if (strings_fill & (1 << i)) {
			numberOfStrings++;
		}
	}
	
	//ktabedit::ktabLog << "String played = " << (int)numberOfStrings << "\n";
	
	QVector<char> notes_strings;
	
	if (strings_fill & 64) notes_strings.push_back(0);
	if (strings_fill & 32) notes_strings.push_back(1);
	if (strings_fill & 16) notes_strings.push_back(2);
	if (strings_fill & 8)  notes_strings.push_back(3);
	if (strings_fill & 4)  notes_strings.push_back(4);
	if (strings_fill & 2)  notes_strings.push_back(5);
	if (strings_fill & 1)  notes_strings.push_back(6);
	//QValueList<char>::iterator it = notes_strings.begin();
	
	i = 0;
	while (i < numberOfStrings) {
		uchar note_special = getByte();
		uchar note_alteration = 0;
		uchar note_value = 0;
		char chord = 0;
		
		note = new TabNote(i + 1);
		
		//ktabedit::ktabLog << "Note header = " << (int)note_special << "\n";
		
		if (note_special & 0x20) {
			note_alteration = getByte();
			//ktabedit::ktabLog << "note alt�ration " << static_cast<int>(note_alteration)  << "\n";
			
			if (note_alteration == 3) {
				note->setDeadNote(true);
				
				//ktabedit::ktabLog << "Dead note" << "\n";
			} else if (note_alteration == 2) { 
				note->setTieNote(true);
				
				//ktabedit::ktabLog << "Note is linked from another note" << "\n";
			}
			
		}
		
		if (note_special & 0x01) {
			//ktabedit::ktabLog << "note duration != beat duration" << "\n";
			
			uchar note_duration = getByte();
			if(note_duration > 128) note_duration-=256;
			
			//ktabedit::ktabLog << static_cast<int>(note_duration) << "\n";
			
			// NTuplet
			//
			note->setNTuplet(getByte() - 1);
		}
		
		if (note_special & 0x10) {
// 			//ktabedit::ktabLog << "Note nuance" << "\n";
			note->setDynamic(static_cast<Dynamic>(getByte()));
		}
		
		if (note_special & 0x20) {
			note_value = getByte();
			//chord = (*it);
			chord = notes_strings[i];
			//ktabedit::ktabLog << "Valeur de la note =" << static_cast<int>(note_value) << " corde = " << 5 -  static_cast<int>(chord) << "\n";
			if (note_value == 255) note_value = 0;
		}
		
		if (note_special & 0x20) {
			
// 			//ktabedit::ktabLog << "Ajout de la note :" << static_cast<int>(note_value) << " corde : " << 5 -  static_cast<int>(chord) << "\n";
// 			//ktabedit::ktabLog << "beat = " << (int)beatduration << "\n";
			switch(beatduration) {
			case 0:
				note->setDuration(Quarter);
				time->setDuration(Quarter);
				break;
			case 1:
				note->setDuration(Eighth);
				time->setDuration(Eighth);
				break;
			case 2:
				note->setDuration(Sixteenth);
				time->setDuration(Sixteenth);
				break;
			case 3:
				note->setDuration(ThirthSecond);
				time->setDuration(ThirthSecond);
				break;
			case 4:
				// Quadruple croche
				note->setDuration(SixtyFourth);
				time->setDuration(SixtyFourth);
				break;
			case 0xff:
				note->setDuration(Half);
				time->setDuration(Half);
				break;
			case 0xfe:
				note->setDuration(Whole);
				time->setDuration(Whole);
				break;
// 			default:
// 				//ktabedit::ktabLog << "beat " << beatduration << "\n";
			}
			
			note->setFret(note_value);
			
			noteLength = 1;
		}
		
		
		if (note_special & 0x80) {
			//ktabedit::ktabLog << "fingerprint" << "\n";
			
			// Left hand
			//
			note->setFingeringLeft(static_cast<TabFingering>(getByte()));
			
			// Right hand
			//
			note->setFingeringRight(static_cast<TabFingering>(getByte()));
		}
		
		if (note_special & 0x40) {
			//ktabedit::ktabLog << "Accentuated note" << "\n";
			note->setAccentuated(true);
		}
		
		if (note_special & 0x04) {
			//ktabedit::ktabLog << "Ghost note" << "\n";
			note->setGhostNote(true);
		}
		
		if (note_special & 0x08) {
			readEffectsOnNote(note->effect());
		}
		
		if (note_special & 0x02) {
			//ktabedit::ktabLog << "Dotted note" << "\n";
			note->setDotted(true);
		}
		
		time->setString(chord, note);
		//++it;
		i++;
	}
}


void GuitarPro4::writeDummies(uint i)
{
	for (uint j = 0; j < i; j++)
		mFile.putch(0x00);
}

void GuitarPro4::writeByte(char c)
{
	mFile.putch(c);
}

void GuitarPro4::writeLong(long l)
{
	char *temp = reinterpret_cast<char *>(&l);
	
	mFile.putch(temp[0]);
	mFile.putch(temp[1]);
	mFile.putch(temp[2]);
	mFile.putch(temp[3]);
}

void GuitarPro4::writeColor(const QColor &color)
{
	writeByte(color.blue());
	writeByte(color.green());
	writeByte(color.red());
	
	writeDummies(1);
}

void GuitarPro4::writeString(const QString &s)
{
	if (s.length() > 0) {
		writeLong(s.length() + 1);
		
		writeByte(s.length());
		mFile.writeBlock(s.toAscii(), s.length());
	} else {
		writeLong(1);
		writeByte(0);
	}
}

void GuitarPro4::writeStringNoInc(const QString &s, int i)
{
	writeByte(s.length());
	mFile.writeBlock(s.toAscii(), s.length());
	
	writeDummies(i - s.length());
}

void GuitarPro4::writeHeader(const TabSong& tabSong)
{
	const QString gProId("FICHIER GUITAR PRO v4.00");
	
	// Write file signature
	//
	writeByte(gProId.length());
	mFile.writeBlock(gProId.toAscii(), gProId.length());
	
	// Now it's time to parse the whole thing
	// First the header: general infos
	//
	writeDummies(31 - gProId.length() - 1);
	
	writeString(tabSong.title());
	writeString(tabSong.subTitle());
	writeString(tabSong.artist());
	writeString(tabSong.album());
	writeString(tabSong.author());
	writeString(tabSong.copyright());
	writeString(tabSong.transcriber());
	writeString(tabSong.instructions());
	
	QString notice = tabSong.comments();
	QStringList noticeLine = QStringList::split('\n', notice);
	ulong noticeNbLines = notice.count('\n');
	
	writeLong(noticeNbLines);
	
	for (QStringList::Iterator it = noticeLine.begin(); it != noticeLine.end(); ++it) {
		 writeString(*it);
	}
	
	writeByte(tabSong.isShuffle());
	
	writeLong(tabSong.lyricsTrack());
	
	for (uchar i = 0; i < 5; i++) {
		writeLong(tabSong.lyricsMeasure(i));
		writeString(tabSong.lyrics(i));
	}
	
	writeLong(tabSong.tempo());
	writeLong(tabSong.key().toAscii());
	writeLong(tabSong.octave());
}

void GuitarPro4::writeMidiHeader(const TabSong &tabSong)
{
	TabSong::const_iterator it(tabSong.begin());
	uint i = 0;
	bool drum = false;
	
	while(it != tabSong.end()) {
		const TabTrack& track = **it;
		const TrackMidiProperties* trackMidiProperties = track.midiProperties();
		
		if (i != 8 && track.mode() != DrumTab) {
			mInstruments[i] = new TrackMidiProperties();
			mInstruments[i]->clone(trackMidiProperties);
			mInstruments[i + 1] = new TrackMidiProperties();
			mInstruments[i + 1]->clone(trackMidiProperties);
			
			i+=2;
		} else if (track.mode() == DrumTab) {
			mInstruments[9] = new TrackMidiProperties();
			mInstruments[9]->clone(trackMidiProperties);
			
			drum = true;
			
			if (i == 8)
				i = 10;
		} else{
			i = 10;
			
			mInstruments[i] = new TrackMidiProperties();
			mInstruments[i]->clone(trackMidiProperties);
			mInstruments[i + 1] = new TrackMidiProperties();
			mInstruments[i + 1]->clone(trackMidiProperties);
			
			i+=2;
		}
		
		++it;
	}
	
	for (; i < 64; i++) {
		if (i == 9 && drum)
			continue;
		
		mInstruments[i] = new TrackMidiProperties();
		mInstruments[i]->setPatch(24);
		mInstruments[i]->setVolume(13);
		mInstruments[i]->setBalance(8);
		mInstruments[i]->setChorus(0);
		mInstruments[i]->setReverb(0);
		mInstruments[i]->setPhaser(0);
		mInstruments[i]->setTremolo(0);
	}
	
	for (i = 0; i < 64; i++) {
		if ((i - 9) % 16 != 0)
			writeLong((char)mInstruments[i]->patch());
		else
			if (mInstruments[9]->patch() == 0xff)
				writeLong(-1);
			else
				writeLong(0);
		
		writeByte(mInstruments[i]->volume());
		writeByte(mInstruments[i]->balance());
		writeByte(mInstruments[i]->chorus());
		writeByte(mInstruments[i]->reverb());
		writeByte(mInstruments[i]->phaser());
		writeByte(mInstruments[i]->tremolo());
		
		writeDummies(2);
	}
	
	for (i = 0; i < 64; i++) {
		delete mInstruments[i];
	}
}

void GuitarPro4::writeBarsHeader(const TabSong &tabSong)
{
	TabSong::const_iterator it(tabSong.begin());
	const TabTrack& track = **it;
	const TabBar* bar;
	uint i = 0;
	uchar barFlag;
	uchar barRythm1 = 0, barRythm2 = 0;
	
	// Number of bars
	//
	writeLong(track.size());
	
	// Number of tracks
	//
	writeLong(tabSong.size());
	
	i = 0;
	while (i < track.size()) {
		bar = track.bar(i);
		barFlag = 0;
		
		if (bar->numerator() != barRythm1) {
			 barRythm1 = bar->numerator();
			 barFlag = barFlag | 1;
		}
		
		if (bar->denominator() != barRythm2) {
			 barRythm2 = bar->denominator();
			 barFlag = barFlag | 2;
		}
		
		if (bar->isRepeatStart()) {
			barFlag = barFlag | 4;
		}
		
		if (bar->repetitions() != 0) {
			barFlag = barFlag | 8;
		}
		
		if (bar->isAlternateEndings()) {
			barFlag = barFlag | 16;
		}
		
		if (bar->color() != QColor() || bar->marker().isEmpty() == false) {
			barFlag = barFlag | 32;
		}
		
		if (bar->key() != QChar(7)) {
			barFlag = barFlag | 64;
		}
		
		if (bar->isDoubleBar()) {
			barFlag = barFlag | 128;
		}
		
		writeByte(barFlag);
		
		if (barFlag & 1)
			writeByte(barRythm1);
		
		if (barFlag & 2)
			writeByte(barRythm2);
		
		if (barFlag & 8)
			writeByte(bar->repetitions());
		
		if (barFlag & 16)
			writeByte(bar->isAlternateEndings());
		
		if (barFlag & 32) {
			writeString(bar->marker());
			writeColor(bar->color());
		}
		
		if (barFlag & 64) {
			writeByte(bar->key().toAscii());
			writeByte(bar->isMinor());
		}
		
		i++;
	}
}

void GuitarPro4::writeTracksHeader(const TabSong &tabSong)
{
	TabSong::const_iterator it(tabSong.begin());
	uint i = 0;
	
	while(it != tabSong.end()) {
		const TabTrack& track = **it;
		
		switch(track.mode()) {
		case FretTab:
			writeByte(0);
			break;
		case DrumTab:
			writeByte(1);
			break;
		case TwelveStringsTab:
			writeByte(2);
			break;
		case BanjoTab:
			writeByte(4);
			break;
		}
		
		writeStringNoInc(track.name(), 40);
		
		if (track.mode() == DrumTab)
			writeLong(6);
		else
			writeLong(track.nbStrings());
		
		for (i = 0; i < track.nbStrings(); i++)
			writeLong(track.tune(i));
		
		for (; i < 7; i++)
			writeLong(0);
		
		writeLong(track.midiPort());
		
		writeLong(track.channel());
		
		writeLong(track.channelEffects());
		
		writeLong(track.nbFrets());
		
		writeLong(track.capo());
		
		writeColor(track.color());
		++it;
	}
}

void GuitarPro4::writeBars(uint nbChords, const TabBar &bar)
{
	//ktabedit::ktabLog << "bar.count() " << bar.size() << "\n";
	writeLong(bar.size());
	
	for (uint i = 0; i < bar.size(); i++) {
		writeTimes(nbChords, *bar.mixer(), *bar.time(i));
	}
}

void GuitarPro4::writeTimes(uint nbChords, const TabMixTableChanges &/*changes*/, const TabTime &times)
{
	uchar cmd = 0;
	TabNoteEffect effects;
	TabMixTableChanges mixChanges;
	
	if (times.isDotted()) {
		cmd = cmd | 1;
	}
	
/*	if (times.isChord()) {
		cmd = cmd | 2;
	}*/
	
	if (times.text().isEmpty() == false) {
		cmd = cmd | 4;
	}
	
/*	if (times != effects) {
		cmd = cmd | 8;
	}*/
	
/*	if (changes != mixChanges) {
		cmd = cmd | 16;
	}*/
	
	if (times.nTuplet()) {
		cmd = cmd | 32;
	}
	
	if (times.isRest()) {
		cmd = cmd | 64;
	}
	
	//ktabedit::ktabLog << "times cmd " << cmd << "\n";
	writeByte(cmd);
	
	if (cmd & 64) {
		//ktabedit::ktabLog << "beat status " << 0x0 << "\n";
		// Beat status : 0x00 empty
		//               0x02 rest
		//
		writeByte(2);
	}
	
	writeBeatDuration(times);
	
	if (cmd & 32) {
		//ktabedit::ktabLog << "tupletDuration " << times.nTuplet() + 1 << "\n";
		writeLong(times.nTuplet() + 1);
	}
	
/*	if (cmd & 2) {
		writeChord(times);
	}*/
	
	if (cmd & 4) {
		writeString(times.text());
	}
	
/*	if (cmd & 8) {
		writeEffects(times);
	}*/
	
/*	if (cmd & 16) {
		writeChanges(times);
	}*/
	
	writeFrets(nbChords, times);
}

void GuitarPro4::writeBeatDuration(const TabTime &times)
{
	uchar duration = 0;
	
	switch(times.duration()) {
	case NoneDuration:
	case HundredTwentyEighth:
	case Quarter:
		duration = 0;
		break;
	case Eighth:
		duration = 1;
		break;
	case Sixteenth:
		duration = 2;
		break;
	case ThirthSecond:
		duration = 3;
		break;
	case SixtyFourth:
		duration = 4;
		break;
	case Half:
		duration = 0xff;
		break;
	case Whole:
		duration = 0xfe;
		break;
	}
	
	//ktabedit::ktabLog << "time duration " << duration << "\n";
	writeByte(duration);
}

void GuitarPro4::writeChord(const TabChord &chord)
{
	if (chord.isSharp() == 0) {
		writeByte(0);
		
		writeString(chord.name());
		writeLong(chord.baseFret());
		
		if (chord.baseFret() != 0) {
			for (uchar i = 0; i < 6; i++)
				writeLong(chord.fret(i));
		}
	} else {
		writeByte(1);
		writeDummies(3);
		
		writeLong(chord.root());
		writeLong(chord.type());
		writeLong(chord.nineElevenThirteen());
		writeLong(chord.bass());
		writeByte(chord.augmentedDiminished());
		writeDummies(3);
		writeByte(chord.addedNote());
		writeStringNoInc(chord.name(), 34);
		writeLong(chord.baseFret());
		
		for (uchar i = 0; i < 6; i++)
			writeLong(chord.fret(i));
		
		writeDummies(28);
		
		for (uchar i = 0; i < 7; i++)
			writeByte(chord.fingering(i));
		
		writeByte(chord.isShowDiagram());
	}
}

void GuitarPro4::writeEffects(const TabTimeEffect &effect)
{
	uchar cmd = 0;
	
	if (effect.isVibrato())
		cmd = cmd | 1;
	
	if (effect.isWideVibrato())
		cmd = cmd | 2;
	
	if (effect.isNaturalHarmonic())
		cmd = cmd | 4;
	
	if (effect.isArtificialHarmonic())
		cmd = cmd | 8;
	
	if (effect.isFadeIn())
		cmd = cmd | 16;
	
	if (effect.tremolo() || effect.isTapping() || effect.isSlapping() || effect.isPopping())
		cmd = cmd | 32;
	
	if (effect.isStroke())
		cmd = cmd | 64;
	
	//ktabedit::ktabLog << "write effects " << cmd << "\n";
	writeByte(cmd);
	
	if (effect.tremolo() || effect.isTapping() || effect.isSlapping() || effect.isPopping()) {
		uchar cmd2 = 0;
		
		if (effect.tremolo())
				cmd2 = 0;
		else {
			if (effect.isTapping())
				cmd2 = 1;
			else if (effect.isSlapping())
				cmd2 = 2;
			else if (effect.isPopping())
				cmd2 = 3;
		}
		
		writeByte(cmd2);
		
		writeDummies(4);
	}
	
	if (effect.isStroke()) {
		writeByte(6 - effect.upStroke());
		writeByte(6 - effect.downStroke());
	}
}

void GuitarPro4::writeChanges(const TabMixTableChanges &mix)
{
	writeByte(mix.instrument());
	writeByte(mix.volume());
	writeByte(mix.balance());
	writeByte(mix.chorus());
	writeByte(mix.reverb());
	writeByte(mix.phaser());
	writeByte(mix.tremolo());
	writeLong(mix.tempo());
	
	if (mix.instrument() != -1)
		writeDummies(1);
	
	if (mix.volume() != -1)
		writeDummies(1);
	
	if (mix.balance() != -1)
		writeDummies(1);
	
	if (mix.chorus() != -1)
		writeDummies(1);
	
	if (mix.reverb() != -1)
		writeDummies(1);
	
	if (mix.phaser() != -1)
		writeDummies(1);
	
	if (mix.tremolo() != -1)
		writeDummies(1);
}

void GuitarPro4::writeFrets(uint nbChords, const TabTime &times)
{
	uchar string = 0;
	uchar cmd;
	
	for (uchar i = 0; i < nbChords; i++)
		if (times.string(i)->isEmpty() == false)
			string = string | (1 << (6 - i));
	
	//ktabedit::ktabLog << "string " << string << "\n";
	writeByte(string);
	
	for (uchar i = 0; i < nbChords; i++) {
		cmd = 0;
		TabNote* note = times.string(i);
		
		if (note->isEmpty() == true)
			continue ;
		
		// if (note duration != beatDuration)
		//	cmd = 1;
		
		if (note->isDotted())
			cmd = cmd | 2;
		
		if (note->isGhostNote())
			cmd = cmd | 4;
		
		if (note->bendType() != TabBend::NoneBend || note->isHammerOnPullOff() || note->slide() != NoneSlide || note->isLetRing() || note->graceNoteFret())
			cmd = cmd | 8;
		
		if (note->dynamic() != NoneDynamic)
			cmd = cmd | 16;
		
		if (note->isDeadNote() || note->isTieNote() || note->isEmpty() == false)
			cmd = cmd | 32;
		
		if (note->isAccentuated())
			cmd = cmd | 64;
		
		if (note->fingeringLeft() != NoneFingering || note->fingeringLeft() != NoneFingering)
			cmd = cmd | 128;
		
		//ktabedit::ktabLog << "chord = " << i << " cmd " << cmd << "\n";
		writeByte(cmd);
		
		if (cmd & 32) {
			uchar effectCmd;
			
			if (note->isDeadNote())
				effectCmd = 3;
			else if (note->isTieNote())
				effectCmd = 2;
			else
				effectCmd = 1;
			
			//ktabedit::ktabLog << "cmd & 32 = " << effectCmd << "\n";
			writeByte(effectCmd);
		}
		
		if (cmd & 16)
			writeByte(note->dynamic());
		
		if (cmd & 32) {
			//ktabedit::ktabLog << "cmd & 32 = " << note->fret() << "\n";
			writeByte(note->fret());
		}
		
		if (cmd & 128) {
			writeByte(note->fingeringLeft());
			writeByte(note->fingeringRight());
		}
		
		if (cmd & 8) {
			uchar effectCmd = 0;
			
			if (note->bendType() != TabBend::NoneBend)
				effectCmd = 1;
			
			if (note->isHammerOnPullOff())
				effectCmd = effectCmd | 2;
			
			if (note->slide() != NoneSlide)
				effectCmd = effectCmd | 4;
			
			if (note->isLetRing())
				effectCmd = effectCmd | 8;
			
			if (note->graceNoteFret())
				effectCmd = effectCmd | 16;
			
			//ktabedit::ktabLog << "cmd & 8 = " << effectCmd << "\n";
			writeByte(effectCmd);
			
			if (effectCmd & 1) {
				writeByte(note->bendType());
				writeLong(note->bendValue());
				writeLong(note->sizeOfBendPoints());
				
				for (int i = 0; i < note->sizeOfBendPoints(); ++i) {
					writeLong(note->bendPoint(i)->position());
					writeLong(note->bendPoint(i)->height());
					writeByte(note->bendPoint(i)->tabVibrato());
				}
			}
			
			if (effectCmd & 16) {
				writeByte(note->graceNoteFret());
				writeByte(note->graceNoteDynamic());
				writeByte(note->graceNoteTransition());
				writeByte(note->graceNoteDuration());
			}
		}
	}
}

bool GuitarPro4::saveFile(const QString &fileName, const TabSong &tabSong)
{
	TabSong::const_iterator it(tabSong.begin());
	const uint trackCount = (*it)->size();
	uint i, j;
	
	// Open file
	//
	mFile.setName(fileName);
	
	if (!mFile.open(IO_WriteOnly)) {
		//ktabedit::ktabLog << "Cannot write file" << "\n";
		throw "Cannot open file";
	}
	
	writeHeader(tabSong);
	
	writeMidiHeader(tabSong);
	
	writeBarsHeader(tabSong);
	
	writeTracksHeader(tabSong);
	
	//ktabedit::ktabLog << "GuitarPro4::SaveFile\n";
	i = 0;
	while (i < trackCount) {
		it = tabSong.begin();
		
		j=0;
		//ktabedit::ktabLog << "[mesure = " << i << "]\n";
		while (it != tabSong.end()) {
			const TabTrack& track = **it;
			//ktabedit::ktabLog << "[piste = " << j++ << "]\n";
			writeBars(track.nbStrings(), *track.bar(i));
			
			++it;
		}
		
		i++;
	}
	
	writeLong(0);
	
	return false;
}
