/****************************************************************************************/
/*											*/
/* 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; (See "LICENSE.GPL"). If not, write to the Free Software Foundation, Inc.,	*/
/* 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.				*/
/*											*/
/*--------------------------------------------------------------------------------------*/
/*											*/
/*		Joerg Anders, TU Chemnitz, Fakultaet fuer Informatik, GERMANY		*/
/*		ja@informatik.tu-chemnitz.de						*/
/*											*/
/*											*/
/****************************************************************************************/

#include "config.h"
#if GCC_MAJ_VERS > 2
#include <fstream>
#else
#include <fstream.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include "voice.h"
#include "resource.h"
#include "rest.h"
#include "staff.h"
#include "midimapper.h"
#include "timesig.h"
#include "transpainter.h"
#include "mainframewidget.h"
#include "numberdisplay.h"
#include "chord.h"
#include "sign.h"
#include "tempotrack.h"

#include <kmessagebox.h>
#include <klocale.h>

#define PAGEBORDER 8

#define LEFT_BORDER 20
#define SELECTHEIGHT 200

#define TRILL_MIDI_LENGTH (NOTE32_LENGTH)
#define ARPEGGIO_MIDI_LENGTH (NOTE64_LENGTH)
#define DYNAMIC_PRECISION (NOTE32_LENGTH)

#define MAX_LINE_IN_EDITOR 80

undostr NVoice::undoelem_[MAXUNDO];
int NVoice::undoptr_;
int NVoice::undocounter_;
int NVoice::lastundoptr_;

undostr NVoice::redoelem_[MAXUNDO];
int NVoice::redoptr_;
int NVoice::redocounter_;

/* ------------- creating voice -------------------------------------------------*/

NVoice::NVoice(NStaff *staff, NMainFrameWidget *mainWidget, bool isFirstVoice) :
wordPattern1_("[^ \r\n\t][^ \r\n\t]*"), wordPattern2_("<[^>\r\n\t]*>"), escapedApostroph_("\\") {

	int i;
	mainWidget_ = mainWidget;
	firstVoice_ = isFirstVoice;
	theStaff_ = staff;
	main_props_ = &(mainWidget->main_props_);
	midiEndTime_ = 0;
	currentElement_ = 0;
	yRestOffs_ = 0;
	virtualChord_.setAutoDelete(true);
	octave_ = -1;
	firstVolume_ = true;
	voiceSet_ = false;
	muted_ = false;
	stemPolicy_ = STEM_POL_INDIVIDUAL;
	startElement_ = endElement_ = 0;
	invalidateReUndo(true);
	for (i = 0; i < MIDI_EVENT_RING; i += 2) {
		midievents_[i].next = &(midievents_[(i+2) % MIDI_EVENT_RING]);
		midievents_[i].notehalt = &(midievents_[i+1]);
	}
}

NVoice::~NVoice() {
	musElementList_.setAutoDelete(true);
	musElementList_.clear();
	virtualChord_.setAutoDelete(true);
	virtualChord_.clear();
	invalidateReUndo(true);
}



/*---------------------- setting voice properies -----------------------------------------*/

void NVoice::emptyVoice() {
	musElementList_.clear();
	virtualChord_.clear();
	currentElement_ = 0;
	invalidateReUndo(true);
}

void NVoice::getChordDiagramms(QList<chordDiagramName> *cdiagList, bool *gridsused, bool firstcall, bool *gridproblem) {
	NMusElement *elem;
	NChordDiagram *diag;
	chordDiagramName *diag_name;
	int oldidx;
	bool firstElem = true;
	int max_underscores;

	oldidx = musElementList_.at();
	for (elem = musElementList_.first(); elem;  elem = musElementList_.next()) {
		if ((diag = elem->getChordChordDiagram()) == NULL) continue;
		max_underscores = -1;
		for (diag_name = cdiagList->first(); diag_name; diag_name = cdiagList->next()) {
			if (diag_name->cdiagramm->isEqual(diag)) {
				max_underscores = -2;
				break;
			}
			if (diag_name->cdiagramm->isAmbigous(diag)) {
				if (diag_name->NumOfUnderscores > max_underscores) max_underscores = diag_name->NumOfUnderscores;
			}
		}
		if (firstcall && firstElem) {
			*gridsused = diag->showDiagram_;
		}
		else {
			if (*gridsused != diag->showDiagram_) {
				*gridproblem = true;
				*gridsused = true;
			}
		}
		if (max_underscores > -2) cdiagList->append(new chordDiagramName(diag, max_underscores+1));
		firstElem = false;
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
				
}

void NVoice::paperDimensiones(int width) {
	NNote *note;
	theStaff_->paperDimensiones(width);
	for (note = virtualChord_.first(); note; note = virtualChord_.next()) {
		note->tie_start_point_up = QPoint((int) ((float) (width +5)  / main_props_->zoom), note->tie_start_point_up.y());
		note->tie_start_point_down = QPoint((int) ((float) (width +5)  / main_props_->zoom), note->tie_start_point_down.y());
		note->tie_back_point_up = QPoint((int) ((float) (width +2)  / main_props_->zoom), note->tie_back_point_up.y());
		note->tie_back_point_down = QPoint((int) ((float) (width +2)  / main_props_->zoom), note->tie_back_point_down.y());
	}
}


/*--------------------------------- search for something in voice ----------------------------- */

int NVoice::getElemState(int *state, int *state2, bool *playable) {
	NChord *chord;
	*state = 0;
	*playable = false;
	if (!currentElement_) return -1;
	*state = currentElement_->status_;
	if (currentElement_->getType() == T_CHORD) {
		chord = (NChord *) currentElement_;
		*state |= chord->getActualNote()->status;
	}
	*state2 = currentElement_->status2_;
	if (*playable = (currentElement_->getType() & PLAYABLE)) {
		return currentElement_->getSubType();
	}
	return -1;
}

int NVoice::checkElementForNoteInsertion(const int line, const QPoint p, int *state, int *state2, bool *playable, bool *delete_elem, bool *insertNewNote, int offs) {
	bool found;
	NMusElement *ac_elem;
	NChord *chord;
	int val;

	*state2 = *state = 0;
	*playable = false;

	found = false;
	ac_elem = musElementList_.first();
	while (!found && ac_elem != 0) {
		switch (val = ac_elem->intersects_horizontally(p)) {
			case 0: found = true; break;
			case -1:
				if (currentElement_) {
					currentElement_->setActual(false);
					currentElement_->draw();
				}
				*delete_elem = 0;
				currentElement_ = 0;
				return -1;
			default: ac_elem = musElementList_.next();
		}
	}
	if (currentElement_) {
		currentElement_->setActual(false);
		currentElement_->draw();
	}
	if (!found) {
		currentElement_ = 0;
		*delete_elem = 0;
		return -1;
	}
	currentElement_ = ac_elem;
	currentElement_->setActual(true);
	*state = currentElement_->status_;
	*state2 = currentElement_->status2_;
	if (currentElement_->getType() == T_CHORD) {
		chord = (NChord *) currentElement_;
		if (chord->setActualNote(line))  {
			if (*delete_elem) {
				if (deleteActualNote()) {
					*delete_elem = false; /* Otherwise there's only one note --> delete chord */
				}
			}
			*insertNewNote = false; /* avoid insertion if successfully deleted */
		}
		else {
			if (*insertNewNote) {
				if (line <= MAXLINE && line >= MINLINE) {
					 insertNewNoteAt(line, p, offs);
					*insertNewNote = false; /* Otherwise insert new chord */
				}
				else {
					currentElement_->setActual(false);
					currentElement_ = 0;
					return -1;
				}
			}
			else {
				currentElement_->setActual(false);
				currentElement_ = 0;
			}
			*delete_elem = 0;
			return -1;
		}
		*state |= chord->getActualNote()->status;
	}
	if (*playable = (currentElement_->getType() & PLAYABLE)) {
		return currentElement_->getSubType();
	}
	return -1;
}

bool NVoice::checkElementForElementInsertion(const QPoint p) {
	bool found;
	NMusElement *ac_elem;

	found = false;
	ac_elem = musElementList_.first();
	while (!found && ac_elem != 0) {
		switch (ac_elem->intersects(p)) {
			case 0: found = true; break;
			case -1:
				if (currentElement_) {
					currentElement_->setActual(false);
					currentElement_->draw();
				}
				return false;
			default: ac_elem = musElementList_.next();
		}
	}
	if (currentElement_) {
		currentElement_->setActual(false);
		currentElement_->draw();
	}
	if (!found) {
		currentElement_ = 0;
		return false;
	}
	currentElement_ = ac_elem;
	currentElement_->setActual(true);
	return true;
}

void NVoice::findAppropriateElems() {
	bool found_start, found_end;
	int xpos0, xpos1;

	
	startElement_ = endElement_ = 0;
	if (musElementList_.count() < 1) return;
	if (!NResource::voiceWithSelectedRegion_->startElement_ || !NResource::voiceWithSelectedRegion_->endElement_) return;
	xpos0 = (NResource::voiceWithSelectedRegion_->endElementIdx_ > NResource::voiceWithSelectedRegion_->startElemIdx_) ?
		 NResource::voiceWithSelectedRegion_->startElement_->getXpos() : NResource::voiceWithSelectedRegion_->endElement_->getXpos();
	xpos1 = (NResource::voiceWithSelectedRegion_->endElementIdx_ > NResource::voiceWithSelectedRegion_->startElemIdx_) ?
		 NResource::voiceWithSelectedRegion_->endElement_->getBbox()->right() : NResource::voiceWithSelectedRegion_->startElement_->getBbox()->right();
	startElemIdx_ = searchPositionAndUpdateSigns(xpos0, &startElement_, &found_start);
	endElementIdx_ = searchPositionAndUpdateSigns(xpos1, &endElement_, &found_end);
	
	if (!found_start && !found_end) {
		startElement_ = endElement_ = 0;
		return;
	}
	if (found_start && !found_end) {
		endElementIdx_ = musElementList_.count() - 1;
		endElement_ = musElementList_.getLast();
	}
	else if (!found_start) {
		NResource::abort("NVoice::findAppropriateElems: internal error");
	}
	else {
		if ((endElement_ = musElementList_.prev()) == 0) {
			startElement_ = endElement_ = 0;
			return;
		}
		endElementIdx_ = musElementList_.at();
	}
}


void NVoice::grabElements() {
	int x0, x1, idx;
	bool found;
	NMusElement *ac_elem;

	clipBoard_.clear();
	if (startElement_ == 0) printf("startElement_ == 0\n");
	if (endElement_ == 0) printf("endElement_ == 0\n");

	if (!startElement_ || !endElement_) return;
	x0 = (endElementIdx_ > startElemIdx_) ? startElemIdx_ : endElementIdx_;
	x1 = (endElementIdx_ > startElemIdx_) ? endElementIdx_ : startElemIdx_;
	found = false;
	ac_elem = musElementList_.at(x0);

	idx = x0;
	while (idx <= x1  && ac_elem != 0) {
		clipBoard_.append(ac_elem);
		ac_elem = musElementList_.next();
		idx = musElementList_.at();
	}
}

void NVoice::findStartElemAt(int x0, int x1) {
	int xp, dist, last_idx, mindist = (1 << 30);
	bool found = false;
	NMusElement *ac_elem, *last_elem;

	if (x0 <= x1) {
		ac_elem = musElementList_.first();
		while (!found && ac_elem != 0) {
			xp = ac_elem->getXpos();
			dist = abs(xp - x0);
			if (dist <= mindist) {
				mindist = dist;
				last_elem = ac_elem;
				last_idx = musElementList_.at();
				ac_elem = musElementList_.next();
			}
			else {
				startElement_ = last_elem;
				startElemIdx_ = last_idx;
				found = true;
			}
		}
		if (!found) {
			startElement_ = musElementList_.last();
			startElemIdx_ = musElementList_.at();
		}
	}
	else {
		ac_elem = musElementList_.last();
		while (!found && ac_elem != 0) {
			xp = ac_elem->getBbox()->right();
			dist = abs(xp - x0);
			if (dist <= mindist) {
				mindist = dist;
				last_elem = ac_elem;
				last_idx = musElementList_.at();
				ac_elem = musElementList_.prev();
			}
			else {
				startElement_ = last_elem;
				startElemIdx_ = last_idx;
				found = true;
			}
		}
		if (!found) {
			startElement_ = musElementList_.first();
			startElemIdx_ = musElementList_.at();
		}
	}
}


void NVoice::trimmRegion(int *x0, int *x1) {
	int x0n;
	NMusElement *ac_elem;
	bool found;
	if (!startElement_) return;
	found = false;
	if (startElemIdx_ < 0) return;
	ac_elem = musElementList_.at(startElemIdx_);
	if (ac_elem == 0) printf("ac_elem nicht gefunden\n");
	if (*x0 <= *x1) {
		x0n = startElement_->getBbox()->left();
		while (!found && ac_elem != 0) {
			if (ac_elem->getBbox()->right() > *x1) {
				found = true;
				endElement_ = ac_elem;
				endElementIdx_ = musElementList_.at();
				*x1 = ac_elem->getBbox()->right();
			}
			else {
				ac_elem = musElementList_.next();
			}
		}
		if (!found) {
			endElement_ = musElementList_.last();
			if (endElement_) {
				endElementIdx_ = musElementList_.at();
			}
		}
	}
	else {
		x0n = startElement_->getBbox()->right();
		while (!found && ac_elem != 0) {
			if (ac_elem->getBbox()->left() < *x1) {
				found = true;
				endElement_ = ac_elem;
				endElementIdx_ = musElementList_.at();
				*x1 = ac_elem->getBbox()->left();
			}
			else {
				ac_elem = musElementList_.prev();
			}
		}
		if (!found) {
			endElement_ = musElementList_.first();
			if (endElement_) {
				endElementIdx_ = musElementList_.at();
			}
		}
	}
	*x0 = x0n;
}

bool NVoice::trimmRegionToWholeStaff(int *x0, int *x1) {
	NMusElement *elem;

	findStartElemAt(0, 10 /* dummy */);
	if (!startElement_) return false;
	if (startElemIdx_ < 0) return false;
	elem = musElementList_.getLast();
	if (elem == 0) return false;
	endElement_ = elem;
	endElementIdx_ = musElementList_.count() - 1;
	*x0 = startElement_->getBbox()->left();
	*x1 = elem->getBbox()->right();
	return true;
}


bool NVoice::wholeTupletDeleted(NMusElement *ac_elem, int posOfLast) {
	NMusElement *lastTupletElem;

	lastTupletElem = ac_elem->getTupletList()->last();
	if (lastTupletElem->getXpos() <= posOfLast) {
		return true;
	}
	return false;
}
		
bool NVoice::wholeBeamDeleted(NChord *ac_elem, int posOfFirst, int posOfLast) {
	NChord *lastBeamedChord, *firstBeamedChord;

	lastBeamedChord = ac_elem->getBeamList()->last();
	firstBeamedChord = ac_elem->getBeamList()->first();
	return (firstBeamedChord->getXpos() >= posOfFirst && lastBeamedChord->getXpos() <= posOfLast);
}
		

void NVoice::deleteBlock() {
	int x0, x1, idx;
	bool found = false;
	NNote *note;
	QList<NNote> *partlist;
	NMusElement *ac_elem, *stop_elem, *start_elem;
	NChord *chord;

	if (!startElement_ || !endElement_) return;
	x0 = (endElementIdx_ > startElemIdx_) ? startElemIdx_ : endElementIdx_;
	x1 = (endElementIdx_ > startElemIdx_) ? endElementIdx_ : startElemIdx_;
	if (currentElement_) {
		currentElement_->setActual(false);
		currentElement_ = 0;
	}
	idx = x0;
	stop_elem = musElementList_.at(x1);
	start_elem = ac_elem = musElementList_.at(x0);
	createUndoElement(x0, x1 - x0 + 1, -(x1 - x0 + 1));
	while (ac_elem != 0 && !found) {
		found = ac_elem == stop_elem;
		if (ac_elem->getType() == T_CHORD) {
			chord = (NChord *) ac_elem;
			if ((ac_elem->status_ & STAT_TUPLET) && !wholeTupletDeleted(ac_elem, stop_elem->getXpos())) {
				ac_elem->breakTuplet();
			}
			if (chord->status_ & STAT_BEAMED) {
				bool wh;
				if (!(wh = wholeBeamDeleted(chord, start_elem->getXpos(), stop_elem->getXpos())) && (chord->lastBeamed() || chord->beamHasOnlyTwoChords())) {
					chord->breakBeames();
				}
				else if (!wholeBeamDeleted(chord, start_elem->getXpos(), stop_elem->getXpos())) {
					chord->removeFromBeam();
				}
			}
			chord->checkSlures();
			musElementList_.remove();
			partlist = chord->getNoteList();
			for (note = partlist->first(); note; note = partlist->next()) {
				reconnectDeletedTies(note);
			}
		}
		else {
			if ((ac_elem->status_ & STAT_TUPLET) && !wholeTupletDeleted(ac_elem, stop_elem->getXpos())) {
				ac_elem->breakTuplet();
			}
			musElementList_.remove();
		}
		ac_elem = musElementList_.current();
		idx = musElementList_.at();
	}
}

void NVoice::resetSlured() {
	NChord *chord;
	if (!currentElement_) return;
	if (currentElement_->getType() != T_CHORD) return;
	chord = (NChord *) currentElement_;
	if (!(chord->status_ & STAT_SLURED)) return;
	createUndoElement(currentElement_, 1, 0);
	chord->setSlured(false);
}

void NVoice::setSlured() {
	bool found;
	int x0, x1, idx;
	NMusElement *ac_elem;
	NChord *slured_chord, *partner;

	if (!startElement_ || !endElement_) return;
	x0 = (endElementIdx_ > startElemIdx_) ? startElemIdx_ : endElementIdx_;
	x1 = (endElementIdx_ > startElemIdx_) ? endElementIdx_ : startElemIdx_;
	if (currentElement_) {
		currentElement_->setActual(false);
		currentElement_ = 0;
	}
	found = false;
	idx = x0;
	ac_elem = musElementList_.at(x0);
	createUndoElement(x0, x1 - x0 + 1, 0);
	while (!found && ac_elem != 0 && idx <= x1) {
		if (ac_elem->getType() == T_CHORD) {
			slured_chord = (NChord *) ac_elem;
			found = true;
		}
		ac_elem = musElementList_.next();
		idx = musElementList_.at();
	}
	if (!found) {
		deleteLastUndo();
		return;
	}
	found = false;
	ac_elem = musElementList_.at(x1);
	while (!found && ac_elem != 0) {
		if (ac_elem->getType() == T_CHORD) {
			partner = (NChord *) ac_elem;
			found = true;
		}
		ac_elem = musElementList_.next();
	}
	if (!found) {
		deleteLastUndo();
		return;
	}
	slured_chord->setSlured(true, partner);
}

void NVoice::reconnectBeames() {
	int oldidx;
	NMusElement *ac_elem;
	NChord *chord;
	QList<NChord> *beamlist = new QList<NChord>();

	oldidx = musElementList_.at();
	ac_elem = currentElement_;
	if (musElementList_.find(currentElement_) == -1) {
		NResource::abort("reconnectBeames: internal error");
	}
	ac_elem->calculateDimensionsAndPixmaps();
	chord = (NChord *) ac_elem;
	beamlist->append((NChord *) ac_elem);
	ac_elem = musElementList_.prev();
	while (ac_elem && (ac_elem->status_ & STAT_BEAMED) && !ac_elem->lastBeamed()) {
		ac_elem->calculateDimensionsAndPixmaps();
		beamlist->insert(0, (NChord *) ac_elem);
		ac_elem = musElementList_.prev();
	}
	chord->computeBeames(beamlist, stemPolicy_);
	if (oldidx >= 0) musElementList_.at(oldidx);
}

void NVoice::reconnectTuplets() {
	int oldidx;
	int numNotes, playtime;
	NMusElement *ac_elem;
	QList<NMusElement> *tupletlist = new QList<NMusElement>();

	oldidx = musElementList_.at();
	ac_elem = currentElement_;
	if (musElementList_.find(ac_elem) == -1) {
		NResource::abort("NVoice::reconnectTuplets: internal error");
	}
	numNotes = ac_elem->getNumNotes();
	playtime = ac_elem->getPlaytime();
	ac_elem->calculateDimensionsAndPixmaps();
	tupletlist->append(ac_elem);
	ac_elem = musElementList_.prev();
	while (ac_elem && (ac_elem->status_ & STAT_TUPLET) && !(ac_elem->status_ & STAT_LAST_TUPLET)) {
		tupletlist->insert(0, ac_elem);
		ac_elem = musElementList_.prev();
	}
	ac_elem->computeTuplet(tupletlist, numNotes, playtime);
	if (oldidx >= 0) musElementList_.at(oldidx);
}

void NVoice::breakCopiedTuplets() {
	int oldidx;
	NMusElement *ac_elem;

	oldidx = musElementList_.at();
	ac_elem = currentElement_;
	ac_elem->unsetTuplet();
	ac_elem = musElementList_.prev();
	while (ac_elem && (ac_elem->status_ & STAT_TUPLET) && !(ac_elem->status_ & STAT_LAST_TUPLET)) {
		ac_elem->unsetTuplet();
		ac_elem = musElementList_.prev();
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
}



int NVoice::computeSlurDist(NChord *chord) {
	int oldidx,idx;
	NChord *partner;
	char *err = "computeSlurDist: internal error";

	if ((oldidx = musElementList_.find(chord)) == -1) {
		NResource::abort(err, 1);
	}
	if (!(chord->status_ & STAT_SLURED)) NResource::abort(err, 2);
	partner = chord->getSlurPartner();
	if (!partner) NResource::abort(err, 3);
	idx = musElementList_.find(partner);
	if (idx == -1) NResource::abort(err, 4);
	musElementList_.at(oldidx);
	return idx - oldidx;
}

int NVoice::findHighestLineInTrill(NChord *chord)  {
	int trillendX;
	int oldidx;
	int higestline = (1 << 30); 
	bool found = false;
	char *err = "FindHighestLineInTrill: internal error";
	NMusElement *elem;
	
	oldidx = musElementList_.at();
	if (musElementList_.find(chord) < 0) {
		NResource::abort(err, 1);
	}
	trillendX = chord->getTrillEnd();
	for (elem = musElementList_.current(); elem && !found; elem = musElementList_.next()) {
		if (elem->getBbox()->left() > trillendX) {
			found = true;
		}
		switch (elem->getType()) {
			case T_CHORD: 	if (elem->getTopY2() < higestline) higestline = elem->getTopY2();
		}
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
	if (!found || higestline == (1 << 30)) {
		NResource::abort(err, 2);
	}
	return ((theStaff_->staff_props_.base - higestline) / (LINE_DIST / 2));
}

int NVoice::findBorderLineInVa(NChord *chord)  {
	int vaendX;
	int oldidx;
	int higestline = (1 << 30);
	int minline = -2;
	int h;
	bool found = false;
	char *err = "findBorderLineInVa: internal error";
	NMusElement *elem;

	
	oldidx = musElementList_.at();
	if (musElementList_.find(chord) < 0) {
		NResource::abort(err, 1);
	}
	vaendX = chord->getVaEnd();
	for (elem = musElementList_.current(); elem && !found; elem = musElementList_.next()) {
		if (elem->getBbox()->left() > vaendX) {
			found = true;
		}
		switch (elem->getType()) {
			case T_CHORD: if (chord->va_ > 0) {
						if (elem->getTopY2() < higestline) higestline = elem->getTopY2();
						break;
					}
					h = elem->getNoteList()->first()->line - 2;
					if (h < minline) minline = h;
					break;
		}
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
	if (!found || chord->va_ > 0 && higestline == (1 << 30)) {
		higestline = chord->getTopY2();
	}
	if (chord->va_ > 0) {
		return ((theStaff_->staff_props_.base - higestline) / (LINE_DIST / 2)+10);
	}
	return minline - 4;
}


int NVoice::findNoteCountTillTrillEnd(NChord *chord) {
	int notecount = 0, trillendX;
	int oldidx;
	NMusElement *elem;
	bool found = false;

	oldidx = musElementList_.at();
	if (musElementList_.find(chord) < 0) {
		NResource::abort("findNoteCountTillTrillEnd: internal error");
	}
	trillendX = chord->getTrillEnd();
	for (elem = musElementList_.next(); elem && !found; elem = musElementList_.next()) {
		if (elem->getBbox()->left() > trillendX) {
			found = true;
		}
		else {
			switch (elem->getType()) {
				case T_CHORD:
				case T_REST: notecount++;
			}
		}
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
	return notecount;
}

int NVoice::findTimeOfTrillEnd(NChord *chord, int *destmestime, int *mescount) {
	int oldidx;
	int trillendtime, trillendX;
	NMusElement *elem;
	*mescount = 0;
	int measures = 0;
	bool found;
	int idx;
	int lastBarTime = 0;
	oldidx = musElementList_.at();

	if ((idx = musElementList_.find(chord)) < 0) {
		NResource::abort("findTimeOfTrillEnd: internal error");
	}
	found = false;
	for (elem = musElementList_.current(); elem && !found;  elem = musElementList_.prev()) {
		if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
			lastBarTime = elem->midiTime_;
			found = true;
		}
	}

	musElementList_.at(idx);

	trillendtime = chord->midiTime_;
	trillendX = chord->getTrillEnd();
	found = false;
	for (elem = musElementList_.next(); elem && !found;  elem = musElementList_.next()) {
		if (elem->getBbox()->left() > trillendX) {
			found = true;
		}
		else if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
			measures++;
			lastBarTime = elem->midiTime_;
		}
		else {
			switch (elem->getType()) {
				case T_CHORD:
				case T_REST: trillendtime = elem->midiTime_;
						(*mescount) += measures;
						*destmestime = lastBarTime;
						measures = 0;
			}
		}
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
	return trillendtime;
}


int NVoice::findTimeOfSlurEnd(NChord *chord, int *destmestime, int *mescount) {
	int oldidx;
	int idx;
	NMusElement *elem, *slurpartner, *lastBarSym;
	oldidx = musElementList_.at();
	*mescount = 0;
	*destmestime = 0;

	if ((idx = musElementList_.find(chord)) < 0) {
		NResource::abort("findTimeOfSlurEnd: internal error", 1);
	}
	slurpartner = chord->getSlurPartner();
	if (!firstVoice_) {
		if (lastBarSym = theStaff_->countBarSymsBetween(chord->getXpos(), slurpartner->getXpos(), mescount)) {
			*destmestime = lastBarSym->midiTime_;
		}
		if (oldidx >= 0) musElementList_.at(oldidx);
		return slurpartner->midiTime_;
	}
	if ((idx = musElementList_.find(chord)) < 0) {
		NResource::abort("findTimeOfSlurEnd: internal error", 1);
	}
	for (elem = musElementList_.current();elem;elem = musElementList_.prev()) {
		if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
			*destmestime = elem->midiTime_;
			break;
		}
	}
	for (elem = musElementList_.at(idx); elem;  elem = musElementList_.next()) {
		if (elem == slurpartner) {
			if (oldidx >= 0) musElementList_.at(oldidx);
			return slurpartner->midiTime_;

		}
		else if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
			(*mescount)++;
			*destmestime = elem->midiTime_;
		}
	}
	NResource::abort("findTimeOfSlurEnd: internal error", 2);
	return 0; /* dummy */
}

int NVoice::findTimeOfVaEnd(NChord *chord, int *destmestime, int *mescount) {
	int oldidx;
	int vaendtime, vaendX;
	NMusElement *elem;
	*mescount = 0;
	int measures = 0;
	bool found;
	int idx;
	int lastBarTime = 0;
	oldidx = musElementList_.at();

	if ((idx = musElementList_.find(chord)) < 0) {
		NResource::abort("findTimeOfVaEnd: internal error");
	}
	found = false;
	for (elem = musElementList_.current(); elem && !found;  elem = musElementList_.prev()) {
		if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
			lastBarTime = elem->midiTime_;
			found = true;
		}
	}

	musElementList_.at(idx);

	vaendtime = chord->midiTime_;
	vaendX = chord->getVaEnd();
	found = false;
	for (elem = musElementList_.next(); elem && !found;  elem = musElementList_.next()) {
		if (elem->getBbox()->left() > vaendX) {
			found = true;
		}
		else if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
			measures++;
			lastBarTime = elem->midiTime_;
		}
		else {
			switch (elem->getType()) {
				case T_CHORD:
				case T_REST: vaendtime = elem->midiTime_;
						(*mescount) += measures;
						*destmestime = lastBarTime;
						measures = 0;
			}
		}
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
	return vaendtime;
}

int NVoice::findTimeOfDynamicEnd(NChord *chord, int *sourcemestime, int *destmestime, int *mescount) {
	int oldidx;
	int dynamicendtime = -1, dynamicendX;
	int idx;
	NMusElement *elem;
	bool found = false;
	int measures = 0;
	*mescount = 0;
	int lastBarTime = *sourcemestime;

	oldidx = musElementList_.at();
	if ((idx = musElementList_.find(chord)) < 0) {
		NResource::abort("findTimeOfDynamicEnd: internal error");
	}
	dynamicendX = chord->getDynamicEnd();
	for (idx++, elem = musElementList_.next(); elem && !found; idx++, elem = musElementList_.next()) {
		if (elem->getBbox()->left() > dynamicendX) {
			found = true;
		}
		else if (elem->getType() & T_SIGN && (elem->getSubType() & BAR_SYMS)) {
			measures++;
			lastBarTime = elem->midiTime_;
		}
		else {
			switch (elem->getType()) {
				case T_CHORD:
				case T_REST: dynamicendtime = elem->midiTime_;
						(*mescount) += measures;
						*destmestime = lastBarTime;
						measures = 0;
			}
		}
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
	return dynamicendtime;
}

int NVoice::findEndOfCrescendo(NChord *chord) {
	int oldidx;
	int endofcrescendo = -1, dynamicendX;
	NMusElement *elem;
	bool found = false;

	oldidx = musElementList_.at();
	if (musElementList_.find(chord) < 0) {
		NResource::abort("findEndOfCrescendo: internal error");
	}
	dynamicendX = chord->getDynamicEnd();
	elem = chord;
	endofcrescendo = elem->midiTime_ + elem->getMidiLength();
	for (elem = musElementList_.next(); elem && !found; elem = musElementList_.next()) {
		if (elem->getBbox()->left() > dynamicendX) {
			found = true;
		}
		else {
			switch (elem->getType()) {
				case T_CHORD: endofcrescendo = elem->midiTime_ + elem->getMidiLength();
			}
		}
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
	return endofcrescendo;
}

bool NVoice::beginsWithGrace() {
	int oldidx;
	NMusElement *elem;

	oldidx = musElementList_.at();
	elem = musElementList_.first();
	while (elem) {
		if (elem->getType() & PLAYABLE) {
			if (oldidx >= 0) musElementList_.at(oldidx);
			return (elem->getType() == T_CHORD && (elem->status_ & STAT_GRACE));
		}
		elem = musElementList_.next();
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
	return false;
}
	
void NVoice::pasteAtPosition(int xpos, QList<NMusElement> *clipboard, bool complete, int *part_in_current_measure, int *dest_midi_time, int *countof128th) {
	int idx, startidx, i, num = 0;
	bool found;
	NChord *chord;
	QList<NChord> lastSluredClones;
	QList<NChord> *beamlist;
	NMusElement *ac_elem, *elem_before = 0, *clone_elem;
	QList<NMusElement> *clonelist;
	int lastbartime;
	ac_elem = clipboard->first();

	lastSluredClones.setAutoDelete(false);
	*part_in_current_measure = *dest_midi_time = 0;
	if (currentElement_)  {
		currentElement_->setActual(false);
		currentElement_ = 0;
	}
	idx = searchPositionAndUpdateSigns(xpos, &ac_elem, &found, &elem_before, countof128th, 0, 0, &lastbartime);
	if (found && elem_before) {
		if ((elem_before->status_ & STAT_BEAMED) && (ac_elem->status_ & STAT_BEAMED)) {
			if (((NChord *) elem_before)->getBeamList() == ((NChord *) ac_elem)->getBeamList()) {
				currentElement_ = musElementList_.prev();
				breakBeames();
				musElementList_.at(idx);
				currentElement_ = 0;
			}
		}
		if ((elem_before->status_ & STAT_TUPLET) && (ac_elem->status_ & STAT_TUPLET)) {
			if (elem_before->getTupletList() == ac_elem->getTupletList()) {
				currentElement_ = musElementList_.prev();
				breakTuplet();
				musElementList_.at(idx);
				currentElement_ = 0;
			}
		}
	}
	if (found) {
		startidx = idx = musElementList_.at();
		*dest_midi_time = ac_elem->midiTime_;
		*part_in_current_measure = ac_elem->midiTime_ - lastbartime;
	}
	else {
		startidx = musElementList_.count();
		if (startidx < 0) {
			startidx = 0;
		}
		else if (musElementList_.count()) {
			*dest_midi_time = musElementList_.getLast()->midiTime_ + musElementList_.getLast()->getMidiLength();
			*part_in_current_measure = musElementList_.getLast()->midiTime_ + musElementList_.getLast()->getMidiLength() - lastbartime;
		}
	}
	clonelist = new QList<NMusElement>();
	for (ac_elem = clipboard->first(); ac_elem; ac_elem = clipboard->next()) {
		if (!complete) {
			switch (ac_elem->getType()) {
				case T_CHORD: 
				case T_REST: break;
				default: continue;
					 break;
			}
		}
					      
		num++;
		clone_elem = ac_elem->clone();
		if (!complete && ac_elem->getType() == T_CHORD) {
			for (i = 0; i < NUM_LYRICS; ((NChord *) clone_elem)->deleteLyrics(i++));
		}
		clone_elem->setStaffProps(&(theStaff_->staff_props_));
		clone_elem->setMainProps(main_props_);
		if (clone_elem->getType() == T_REST) ((NRest *) clone_elem)->setVoiceOffs(&yRestOffs_);
		clone_elem->setActual(false);
		if (found) {
			musElementList_.insert(idx, clone_elem);
			idx++;
		}
		else {
			musElementList_.append(clone_elem);
		}
		currentElement_ = clone_elem;
		clonelist->append(clone_elem);
		switch (clone_elem->getType()) {
			case T_KEYSIG: ((NKeySig *) clone_elem)->setClef(&theStaff_->actualClef_);
					break;
			case T_CHORD: chord = (NChord *) ac_elem;
				     if (chord->status_ & STAT_SLURED) {
					lastSluredClones.insert(0, (NChord *) clone_elem);
			             }
				     if ((chord->status_ & STAT_PART_OF_SLUR)) {
						if (lastSluredClones.isEmpty()) {
							chord->resetSlurBackward();
						}
						else {
							lastSluredClones.first()->setSlured(true, (NChord *) clone_elem);
							lastSluredClones.remove();
						}
				     }
				     reconnectCopiedTies((NChord *) clone_elem);
				     if (clone_elem->lastBeamed()) {
				     		reconnectBeames();
				     }
			case T_REST:
				     if (clone_elem->status_ & STAT_LAST_TUPLET) {
						if (checkTuplets(clipboard, ac_elem->getTupletList())) {
							reconnectTuplets();
						}
#ifdef AAA /* see below! */
						else {
							breakCopiedTuplets();
						}
#endif
				     }
				     break;
		}
	}
	for (clone_elem = clonelist->first(); clone_elem; clone_elem = clonelist->next()) {
		switch (clone_elem->getType()) {
			case T_CHORD: if (clone_elem->status_ & STAT_BEAMED) {
					chord = (NChord *) clone_elem;
					beamlist = chord->getBeamList();
					if (beamlist->count() < 2 || !lastChordContained(clonelist, beamlist)) {
						chord->resetBeamFlag();
					}
				     }
 				     clone_elem->trill_ = clone_elem->dynamic_ = 0;
			case T_REST:
				    if (clone_elem->status_ & STAT_TUPLET) {
					if (!allElemsContained(clonelist, clone_elem->getTupletList())) {
						clone_elem->resetTupletFlag();
					}
				    }
				    break;
		}
	}
	for (chord = lastSluredClones.first(); chord; chord = lastSluredClones.next()) {
		chord->resetSlurForward();
	}
		
	createUndoElement(startidx, 0, clonelist->count());
	delete clonelist;
}


void NVoice::pasteAtMidiTime(int dest_time, int part_in_measure, int countof128th, QList<NMusElement> *clipboard) {
	int idx, startidx, num = 0;
	bool found;
	NChord *chord;
	QList<NChord> lastSluredClones;
	QList<NChord> *beamlist;
	NMusElement *ac_elem, *elem_before = 0, *clone_elem;
	QList<NMusElement> *clonelist;
	int status;
	int dotcount;
	int diff_total, len, len2, lastElemTime;
	NRest *rest;
	int idx_of_first_inserted_rest = -1;

	if (currentElement_)  {
		currentElement_->setActual(false);
		currentElement_ = 0;
	}
	found = false;
	ac_elem = musElementList_.first();
	while (!found && ac_elem != 0) {
		if (ac_elem->midiTime_ < dest_time) {
			elem_before = ac_elem;
			ac_elem = musElementList_.next();
		}
		else {
			found = true;
		}
	}
	if (found && elem_before) {
		if ((elem_before->status_ & STAT_BEAMED) && (ac_elem->status_ & STAT_BEAMED)) {
			if (((NChord *) elem_before)->getBeamList() == ((NChord *) ac_elem)->getBeamList()) {
				idx = musElementList_.at();
				currentElement_ = musElementList_.prev();
				breakBeames();
				musElementList_.at(idx);
				currentElement_ = 0;
			}
		}
		if ((elem_before->status_ & STAT_TUPLET) && (ac_elem->status_ & STAT_TUPLET)) {
			if (elem_before->getTupletList() == ac_elem->getTupletList()) {
				idx = musElementList_.at();
				currentElement_ = musElementList_.prev();
				breakTuplet();
				musElementList_.next();
				currentElement_ = 0;
			}
		}
	}
	lastElemTime = elem_before ? elem_before->midiTime_ + elem_before->getMidiLength() : 0;
	diff_total = dest_time - lastElemTime - part_in_measure;
	clonelist = new QList<NMusElement>();
	if (diff_total > 0) {
		countof128th *= MULTIPLICATOR;
		len = diff_total % countof128th;
		if (len > 0) {
			while (len >= MULTIPLICATOR) {
				len2 = quant(len, &dotcount, DOUBLE_WHOLE_LENGTH);
				len -= dotcount ? 3 * len2 / 2 : len2;
				diff_total -= dotcount ? 3 * len2 / 2 : len2;
				status = STAT_HIDDEN;
				if (dotcount) status |= STAT_SINGLE_DOT;
				rest = new NRest(main_props_, theStaff_->getStaffPropsAddr(), &yRestOffs_, len2, status); 
				if (found) {
					if (idx_of_first_inserted_rest == -1) idx_of_first_inserted_rest = idx;
					musElementList_.insert(idx++, rest);
				}
				else {
					if (idx_of_first_inserted_rest == -1) idx_of_first_inserted_rest = musElementList_.count();
					musElementList_.append(rest);
				}
			}
		}
		while (diff_total >= MULTIPLICATOR) {
			len2 = quant(countof128th, &dotcount, DOUBLE_WHOLE_LENGTH);
			diff_total -= dotcount ? 3 * len2 / 2 : len2;
			status = STAT_HIDDEN;
			if (dotcount) status |= STAT_SINGLE_DOT;
			rest = new NRest(main_props_, theStaff_->getStaffPropsAddr(), &yRestOffs_, len2, status); 
			if (found) {
				if (idx_of_first_inserted_rest == -1) idx_of_first_inserted_rest = idx;
				musElementList_.insert(idx++, rest);
			}
			else {
				if (idx_of_first_inserted_rest == -1) idx_of_first_inserted_rest = musElementList_.count();
				musElementList_.append(rest);
			}
		}
		while (part_in_measure >= MULTIPLICATOR) {
			len2 = quant(part_in_measure, &dotcount, DOUBLE_WHOLE_LENGTH);
			part_in_measure -= dotcount ? 3 * len2 / 2 : len2;
			status = STAT_HIDDEN;
			if (dotcount) status |= STAT_SINGLE_DOT;
			rest = new NRest(main_props_, theStaff_->getStaffPropsAddr(), &yRestOffs_, len2, status); 
			if (found) {
				if (idx_of_first_inserted_rest == -1) idx_of_first_inserted_rest = idx;
				musElementList_.insert(idx++, rest);
			}
			else {
				if (idx_of_first_inserted_rest == -1) idx_of_first_inserted_rest = musElementList_.count();
				musElementList_.append(rest);
			}
		}
	}
	if (found) {
		startidx = idx = musElementList_.at();
	}
	else {
		startidx = musElementList_.count();
		if (startidx < 0) {
			startidx = 0;
		}
	}
	for (ac_elem = clipboard->first(); ac_elem; ac_elem = clipboard->next()) {
		num++;
		clone_elem = ac_elem->clone();
		clone_elem->setStaffProps(&(theStaff_->staff_props_));
		clone_elem->setMainProps(main_props_);
		if (clone_elem->getType() == T_REST) ((NRest *) clone_elem)->setVoiceOffs(&yRestOffs_);
		clone_elem->setActual(false);
		if (found) {
			musElementList_.insert(idx, clone_elem);
			idx++;
		}
		else {
			musElementList_.append(clone_elem);
		}
		currentElement_ = clone_elem;
		clonelist->append(clone_elem);
		switch (clone_elem->getType()) {
			case T_KEYSIG: ((NKeySig *) clone_elem)->setClef(&theStaff_->actualClef_);
					break;
			case T_CHORD: chord = (NChord *) ac_elem;
				     if (chord->status_ & STAT_SLURED) {
					lastSluredClones.insert(0, (NChord *) clone_elem);
			             }
				     if ((chord->status_ & STAT_PART_OF_SLUR)) {
						if (lastSluredClones.isEmpty()) {
							chord->resetSlurBackward();
						}
						else {
							lastSluredClones.first()->setSlured(true, (NChord *) clone_elem);
							lastSluredClones.remove();
						}
				     }
				     reconnectCopiedTies((NChord *) clone_elem);
				     if (clone_elem->lastBeamed()) {
				     		reconnectBeames();
				     }
			case T_REST:
				     if (clone_elem->status_ & STAT_LAST_TUPLET) {
						if (checkTuplets(clipboard, ac_elem->getTupletList())) {
							reconnectTuplets();
						}
#ifdef AAA /* see below! */
						else {
							breakCopiedTuplets();
						}
#endif
				     }
				     break;
		}
	}
	for (clone_elem = clonelist->first(); clone_elem; clone_elem = clonelist->next()) {
		switch (clone_elem->getType()) {
			case T_CHORD: if (clone_elem->status_ & STAT_BEAMED) {
					chord = (NChord *) clone_elem;
					beamlist = chord->getBeamList();
					if (beamlist->count() < 2 || !lastChordContained(clonelist, beamlist)) {
						chord->resetBeamFlag();
					}
				     }
			case T_REST:
				    if (clone_elem->status_ & STAT_TUPLET) {
					if (!lastElemContained(clonelist, clone_elem->getTupletList())) {
						clone_elem->resetTupletFlag();
					}
				    }
				    break;
		}
	}
	for (chord = lastSluredClones.first(); chord; chord = lastSluredClones.next()) {
		chord->resetSlurForward();
	}
	if (idx_of_first_inserted_rest != -1) {
		createUndoElement(idx_of_first_inserted_rest, 0, clonelist->count() + startidx - idx_of_first_inserted_rest);
	}
	else {
		createUndoElement(startidx, 0, clonelist->count());
	}
	delete clonelist;
}
	

/*-------------------------------- drawing voice ----------------------------------------------*/



void NVoice::draw(int left, int right, bool is_actual) {
	int oldidx;
	NMusElement *elem;
	int flags = (is_actual || main_props_->voiceDisplay->isZero()) ? DRAW_INDIRECT : DRAW_INDIRECT_GREY;
	if (main_props_->voiceDisplay->isZero()) {
		flags |= DRAW_NO_HIDDEN_REST;
	}
	
	oldidx = musElementList_.at();
	for (elem=musElementList_.first(); elem != 0; elem=musElementList_.next()) {
		if (elem->getXposDecorated() < left || elem->getXpos() > right) continue;
		elem->draw(flags);
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
}

/*--------------------- changes due to user interaction ------------------------------------*/

void NVoice::release() {
	if (!currentElement_) return;
	currentElement_->setActual(false);
	currentElement_->draw();
	currentElement_ = 0;
}

void NVoice::makeKeysigAndClefActual() {
	int oldidx, idx;
	NMusElement *elem;
	char *err = "makeKeysigAndClefActual: internal error";

	if ((oldidx = musElementList_.find(currentElement_)) < 0) return;
	for (idx = 0, elem = musElementList_.first(); elem && idx < oldidx; elem = musElementList_.next(), idx++) {
		switch (elem->getType()) {
			case T_CLEF: theStaff_->actualClef_.change((NClef *) elem);
				     theStaff_->actualKeysig_.setClef((NClef *) elem);
				     break;
			case T_KEYSIG: theStaff_->actualKeysig_.change((NKeySig*) elem);
					break;
		}
	}
	if (!elem) NResource::abort(err, 1);
	theStaff_->actualKeysig_.resetAtBar();
	for (elem = musElementList_.at(oldidx - 1); elem; elem = musElementList_.prev()) {
		if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) break;
		if (elem->getType() != T_CHORD) continue;
		((NChord *) elem)->accumulateAccidentals(&(theStaff_->actualKeysig_));
	}
}
				     
		


void NVoice::moveUp(int up) {
	if (!currentElement_) return;
	if (currentElement_->getType() != T_CHORD) return;
	createUndoElement(currentElement_, 1, 0);
	breakTies((NChord *) currentElement_);
	makeKeysigAndClefActual();
	currentElement_->moveUp(up, stemPolicy_, &(theStaff_->actualKeysig_));
	reconnectTiesAtferMove((NChord *) currentElement_);
	if (!NResource::allowInsertEcho_) return;
	NResource::mapper_->playImmediately(&(theStaff_->actualClef_), (NChord *) currentElement_,
		theStaff_->getVoice(), theStaff_->getChannel(), theStaff_->getVolume(), theStaff_->transpose_);
}

void NVoice::moveDown(int down) {
	if (!currentElement_) return;
	if (currentElement_->getType() != T_CHORD) return;
	createUndoElement(currentElement_, 1, 0);
	breakTies((NChord *) currentElement_);
	makeKeysigAndClefActual();
	currentElement_->moveDown(down, stemPolicy_, &(theStaff_->actualKeysig_));
	reconnectTiesAtferMove((NChord *) currentElement_);
	if (!NResource::allowInsertEcho_) return;
	NResource::mapper_->playImmediately(&(theStaff_->actualClef_), (NChord *) currentElement_,
		theStaff_->getVoice(), theStaff_->getChannel(), theStaff_->getVolume(), theStaff_->transpose_);
}

int NVoice::makePreviousElementActual(int *state, int *state2) {
	*state = 0;
	if (!currentElement_) return -1;
	bool was_playable;

	was_playable = (currentElement_->getType() & PLAYABLE);
	if (musElementList_.find(currentElement_) == -1) {
		NResource::abort("makePreviousElementActual: internal error");
	}
	if (musElementList_.prev() == 0) {
		return -1;
	}
	currentElement_->setActual(false);
	currentElement_->draw();
	
	currentElement_ = musElementList_.current();
	currentElement_->setActual(true);
	currentElement_->draw();
	*state = currentElement_->status_;
	if (currentElement_->getType() == T_CHORD) {
		*state |= currentElement_->getNoteList()->first()->status;
	}
	*state2 = currentElement_->status2_;
	if (!was_playable) return -1;
	return currentElement_->getSubType();
}

int NVoice::makeNextElementActual(int *state, int *state2) {
	*state = 0;
	if (!currentElement_) return -1;
	bool was_playable;

	was_playable = (currentElement_->getType() & PLAYABLE);
	if (musElementList_.find(currentElement_) == -1) {
		NResource::abort("makeNextElementActual: internal error");
	}
	if (musElementList_.next() == 0) {
		return -1;
	}
	currentElement_->setActual(false);
	currentElement_->draw();
	
	currentElement_ = musElementList_.current();
	currentElement_->setActual(true);
	currentElement_->draw();
	*state = currentElement_->status_;
	if (currentElement_->getType() == T_CHORD) {
		*state |= currentElement_->getNoteList()->first()->status;
	}
	*state2 = currentElement_->status2_;
	if (!was_playable) return -1;
	return currentElement_->getSubType();
}

void NVoice::changeBodyOfActualElement() {
	if (!currentElement_) return;
	createUndoElement(currentElement_, 1, 0);
	currentElement_->changeBody(main_props_->noteBody);
}


void NVoice::changeActualChord() {
	if (!currentElement_) return;
	createUndoElement(currentElement_, 1, 0);
	currentElement_->changeLength(main_props_->actualLength);
	if (currentElement_->status_ & STAT_TUPLET) {
		currentElement_->breakTuplet();
	}
}

void NVoice::changeActualStem() {
	NChord *chord;
	if (!currentElement_) return;
	if (currentElement_->getType() != T_CHORD) return;
	if (currentElement_->getSubType() > HALF_LENGTH) return;
	chord = (NChord *) currentElement_;
	if ((chord->status_ & STAT_STEM_UP) && main_props_->actualStemDir == STEM_DIR_UP) return;
	if (!(chord->status_ & STAT_STEM_UP) && main_props_->actualStemDir == STEM_DIR_DOWN) return;
	createUndoElement(currentElement_, 1, 0);
	chord->setStemUp(main_props_->actualStemDir == STEM_DIR_UP);
}

void NVoice::breakBeames() {
	NChord *chord;
	QList<NChord> *beamlist;
	int first_beam_idx, last_beam_idx;
	if (!currentElement_) return;
	if (!(currentElement_->status_ & STAT_BEAMED)) return;
	chord = (NChord *) currentElement_;
	beamlist = chord->getBeamList();
	first_beam_idx = musElementList_.find(beamlist->first());
	last_beam_idx = musElementList_.find(beamlist->last());
	if (first_beam_idx < 0 || last_beam_idx < 0) {
		NResource::abort("breakBeames: internal error");
	}
	createUndoElement(first_beam_idx, last_beam_idx - first_beam_idx + 1, 0);
	chord->breakBeames();
}

bool NVoice::lastChordContained(QList<NMusElement> *clonelist, QList<NChord> *beamlist) {
	int oldidx = clonelist->at();
	NChord *lastChord = beamlist->last();
	NMusElement *elem;

	for (elem = clonelist->first(); elem; elem = clonelist->next()) {
		if (elem->getType() != T_CHORD) continue;
		if ((NChord *) elem == lastChord) {
			if (oldidx >= 0) {
				clonelist->at(oldidx);
			}
			return true;
		}
	}
	if (oldidx >= 0) {
		clonelist->at(oldidx);
	}
	return false;
}

bool NVoice::allElemsContained(QList<NMusElement> *clonelist, QList<NMusElement> *tupletlist) {
	NMusElement *elem;

	for (elem = tupletlist->first(); elem; elem = tupletlist->next()) {
		if (clonelist->find(elem) < 0) return false;
	}
	return true;
}

bool NVoice::lastElemContained(QList<NMusElement> *clonelist, QList<NMusElement> *tupletlist) {
	int oldidx = clonelist->at();
	NMusElement *lastelem = tupletlist->last();
	NMusElement *elem;

	for (elem = clonelist->first(); elem; elem = clonelist->next()) {
		if (elem->getType() != T_CHORD && elem->getType() != T_REST) continue;
		if (elem == lastelem) {
			if (oldidx >= 0) {
				clonelist->at(oldidx);
			}
			return true;
		}
	}
	if (oldidx >= 0) {
		clonelist->at(oldidx);
	}
	return false;
}


bool NVoice::checkTuplets(QList<NMusElement> *copielist, QList<NMusElement> *tupletlist) {
	int oldidx = copielist->at();
	bool found;
	NMusElement *elem0, *elem1;

	for (elem0 = tupletlist->first(); elem0; elem0 = tupletlist->next()) {
		found = false;
		for (elem1 = copielist->first(); !found && elem1; elem1 = copielist->next()) {
			if (elem1 == elem0) found = true;
		}
		if (!found) {
			if (oldidx >= 0) copielist->at(oldidx);
			return false;
		}
	}
	if (oldidx >= 0) copielist->at(oldidx);
	return true;
}

void NVoice::breakTuplet() {
	int oldidx;
	QList<NMusElement> *tupletlist;
	int first_trip_idx, last_trip_idx;

	if (!currentElement_) return;
	if (!(currentElement_->status_ & STAT_TUPLET)) return;
	oldidx = musElementList_.at();
	tupletlist = currentElement_->getTupletList();
	first_trip_idx = musElementList_.find(tupletlist->first());
	last_trip_idx = musElementList_.find(tupletlist->last());
	if (first_trip_idx < 0 || last_trip_idx < 0) {
		NResource::abort("breakTuplet: internal error");
	}
	createUndoElement(first_trip_idx, last_trip_idx - first_trip_idx + 1, 0);
	currentElement_->breakTuplet();
	if (oldidx >= 0) musElementList_.at(oldidx);
}

void NVoice::changeActualOffs(int offs) {
	if (!currentElement_) return;
	if (currentElement_->getType() != T_CHORD) return;
	createUndoElement(currentElement_, 1, 0);
	breakTies((NChord *) currentElement_);
	makeKeysigAndClefActual();
	currentElement_->changeOffs(offs, &(theStaff_->actualKeysig_));
	reconnectTiesAtferMove((NChord *) currentElement_);
	NResource::mapper_->playImmediately(&(theStaff_->actualClef_), (NChord *) currentElement_,
		theStaff_->getVoice(), theStaff_->getChannel(), theStaff_->getVolume(), theStaff_->transpose_);
}

void NVoice::setDotted() {
	if (!currentElement_) return;
	createUndoElement(currentElement_, 1, 0);
	currentElement_->setDotted(main_props_->dotcount);
}

void NVoice::setAccent(unsigned int type){
	if (!currentElement_) return;
	if (currentElement_->getType() != T_CHORD) return;
	createUndoElement(currentElement_, 1, 0);
	NChord *chord = (NChord *) currentElement_;
	if (chord->status_ & STAT_STACC)
	    chord->status_ ^= STAT_STACC;
    	for (int i = 19; i <= 23; i++)
	    if (chord->status_ & (1 << i))
    	        chord->status_ ^= (1 << i);
	switch(type){
	    case STAT_STACC: SET_STATUS(main_props_->staccato, chord->status_, STAT_STACC); break;
	    case STAT_SFORZ: SET_STATUS(main_props_->sforzato, chord->status_, STAT_SFORZ); break;
	    case STAT_PORTA: SET_STATUS(main_props_->portato, chord->status_, STAT_PORTA); break;
	    case STAT_STPIZ: SET_STATUS(main_props_->strong_pizzicato, chord->status_, STAT_STPIZ); break;
	    case STAT_SFZND: SET_STATUS(main_props_->sforzando, chord->status_, STAT_SFZND); break;
	    case STAT_FERMT: SET_STATUS(main_props_->fermate, chord->status_, STAT_FERMT); break;
	    default: printf("illegal accent, ID: %i\n", type);
	             fflush(stdout);
	             break;
	}
}

void NVoice::pubAddUndoElement() {
    createUndoElement(currentElement_, 1, 0);
}

void NVoice::setTied() {
	NNote *note;
	NChord *chord;
	if (!currentElement_) return;
	if (currentElement_->getType() != T_CHORD) return;
	chord = (NChord *) currentElement_;
	note = chord->getActualNote(); 
	if (main_props_->tied) {
		if (note->status & STAT_TIED) return;
	}
	else {
		if (!(note->status & STAT_TIED)) return;
	}
	createUndoElement(currentElement_, 1, 0);
	if (main_props_->tied) {
		reconnectTies(note);
		findTieMember(note);
		currentElement_->setTied(main_props_->tied);
	}
	else {
		reconnectDeletedTies(note);
		currentElement_->setTied(main_props_->tied);
	}
}

void NVoice::setArpeggio() {
	NChord *chord;
	if (!currentElement_) return;
	if (currentElement_->getType() != T_CHORD) return;
	chord = (NChord *) currentElement_;
	if (main_props_->arpeggio) {
		if (chord->status_ & STAT_ARPEGG) return;
	}
	else {
		if (!(chord->status_ & STAT_ARPEGG)) return;
	}
	createUndoElement(currentElement_, 1, 0);
	chord->setArpeggio(main_props_->arpeggio);
}

void NVoice::setPedalOn() {
	NChord *chord;
	if (!currentElement_) return;
	if (currentElement_->getType() != T_CHORD) return;
	chord = (NChord *) currentElement_;
	if (main_props_->pedal_on) {
		if (chord->status2_ & STAT2_PEDAL_ON) return;
	}
	else {
		if (!(chord->status2_ & STAT2_PEDAL_ON)) return;
	}
	createUndoElement(currentElement_, 1, 0);
	chord->setPedalOn(main_props_->pedal_on);
}

void NVoice::setPedalOff() {
	NChord *chord;
	if (!currentElement_) return;
	if (currentElement_->getType() != T_CHORD) return;
	chord = (NChord *) currentElement_;
	if (main_props_->pedal_off) {
		if (chord->status2_ & STAT2_PEDAL_OFF) return;
	}
	else {
		if (!(chord->status2_ & STAT2_PEDAL_OFF)) return;
	}
	createUndoElement(currentElement_, 1, 0);
	chord->setPedalOff(main_props_->pedal_off);
}

void NVoice::setBeamed() {
	int count, x0, x1, idx;
	bool found, beamable = true;
	NMusElement *acc_elem;
	QList<NChord> *chordlist;
	NChord *chord;

	if (!startElement_ || !endElement_) return;
	x0 = (endElementIdx_ > startElemIdx_) ? startElemIdx_ : endElementIdx_;
	x1 = (endElementIdx_ > startElemIdx_) ? endElementIdx_ : startElemIdx_;
	idx = x0;
	found = false;
	acc_elem = musElementList_.at(x0);
	chordlist = new QList<NChord>();
	while (!found && acc_elem != 0 && idx <= x1) {
		if (acc_elem->getType() == T_CHORD) {
			if (acc_elem->getSubType() < QUARTER_LENGTH && !(acc_elem->status_ & STAT_BEAMED)) {
				chord = (NChord *) acc_elem;
				chordlist->append(chord);
				acc_elem = musElementList_.next();
				idx = musElementList_.at();
				count = 1;
				found = true;
			}
			else {
				acc_elem = musElementList_.next();
				idx = musElementList_.at();
			}
		}
		else {
			acc_elem = musElementList_.next();
			idx = musElementList_.at();
		}
	}
	if (!found) {
		return;
	}
	x0 = idx;
	found = false;
	while (!found && beamable && acc_elem != 0 && idx <= x1) {
		if (acc_elem->getType() == T_CHORD) {
			if (acc_elem->getSubType() > NOTE8_LENGTH) {
				beamable = false;
			}
			else {
				chord = (NChord *) acc_elem;
				chordlist->append(chord);
				acc_elem = musElementList_.next();
				idx = musElementList_.at();
				count++;
			}
		}
		else {
			beamable = false;
		}
	}
	beamable = beamable && count > 1;
	if (!beamable) {
		return;
	}
	
	x0 = musElementList_.find(chordlist->first());
	x1 = musElementList_.find(chordlist->last());
	if (x0 < 0 || x1 < 0) {
		NResource::abort("setBeamed: internal error");
	}
	createUndoElement(x0, x1 - x0 + 1, 0);
	NChord::computeBeames(chordlist, stemPolicy_);
}

void NVoice::setTuplet(char numNotes, char playtime) {
	int count, x0, x1, idx;
	bool found, tupletable = true;
	NMusElement *acc_elem;
	QList<NMusElement> *elemlist;
	int sum;

	if (!startElement_ || !endElement_) return;
	x0 = (endElementIdx_ > startElemIdx_) ? startElemIdx_ : endElementIdx_;
	x1 = (endElementIdx_ > startElemIdx_) ? endElementIdx_ : startElemIdx_;
	found = false;
	acc_elem = musElementList_.at(x0);
	elemlist = new QList<NMusElement>();
	idx = x0;
	while (!found && acc_elem != 0 && idx < x1) {
		if (acc_elem->getType() & PLAYABLE) {
			sum = acc_elem->getSubType() / MULTIPLICATOR;
			elemlist->append(acc_elem);
			acc_elem = musElementList_.next();
			count = 1;
			found = true;
		}
		else {
			acc_elem = musElementList_.next();
			idx = musElementList_.at();
		}
	}
	if (!found) {
		return;
	}
	found = false;
	while (!found && tupletable && acc_elem != 0 && idx <= x1) {
		if (acc_elem->getType() & PLAYABLE) {
			sum += acc_elem->getSubType() / MULTIPLICATOR;
			elemlist->append(acc_elem);
			acc_elem = musElementList_.next();
			idx = musElementList_.at();
			count++;
		}
		else {
			tupletable = false;
		}
	}
	tupletable = tupletable && count > 1 && (sum % numNotes == 0);
	if (!tupletable) {
		return;
	}
	x0 = musElementList_.find(elemlist->first());
	x1 = musElementList_.find(elemlist->last());
	if (x0 < 0 || x1 < 0) {
		NResource::abort("setTuplet: internal error");
	}
	createUndoElement(x0, x1 - x0 + 1, 0);
	NMusElement::computeTuplet(elemlist, numNotes, playtime);
}

int NVoice::deleteActualElem(int *state, int *state2, bool backspace) {
	NNote *note;
	QList<NNote> *partlist;
	NChord *chord;
	*state2 = *state = 0;
	if (!currentElement_) return -1;
	if (musElementList_.isEmpty()) {
		return -1;
	}
	if (currentElement_->getType() == T_CHORD) {
		chord = (NChord *) currentElement_;
		createUndoElement(currentElement_, 1, -1);
		if (chord->status_ & STAT_TUPLET) {
			chord->breakTuplet();
		}
		if (chord->lastBeamed() || chord->beamHasOnlyTwoChords()) {
			chord->breakBeames();
		}
		else if (chord->status_ & STAT_BEAMED) {
			chord->removeFromBeam();
		}
		if (musElementList_.find(currentElement_) == -1) {
			NResource::abort("deleteActualElem: internal error", 1);
		}
		musElementList_.remove();
		partlist = chord->getNoteList();
		for (note = partlist->first(); note; note = partlist->next()) {
			reconnectDeletedTies(note);
		}
		chord->checkSlures();
	}
	else {
		createUndoElement(currentElement_, 1, -1);
		if (currentElement_->status_ & STAT_TUPLET) {
			currentElement_->breakTuplet();
		}
		if (musElementList_.find(currentElement_) == -1) {
			NResource::abort("deleteActualElem: internal error", 2);
		}
		musElementList_.remove();
	}
	currentElement_ = musElementList_.current();
	if (backspace && currentElement_) {
		if (musElementList_.find(currentElement_) == -1) {
			NResource::abort("deleteActualElem: internal error", 3);
		}
		if (musElementList_.at() != (int) (musElementList_.count() -1)) {
			musElementList_.prev();
		}
	}
	if (!musElementList_.current())  musElementList_.first(); 
	if (currentElement_ = musElementList_.current()) {
		currentElement_->setActual(true);
		*state = currentElement_->status_;
		if (currentElement_->getType() == T_CHORD) {
			partlist = currentElement_->getNoteList();
			*state |= partlist->first()->status;
		}
		*state2 = currentElement_->status2_;
		if (currentElement_->getType() & PLAYABLE) {
			return currentElement_->getSubType();
		}
		return -1;
	}
	return -1;
}

bool NVoice::deleteActualNote() {
	NNote *note;
	NChord *chord;
	if (!currentElement_);
	if (currentElement_->getType() != T_CHORD) {
		NResource::abort("deleteAtLine: internal error(1)");
	}
	chord = (NChord *) currentElement_;
	note = chord->getActualNote();
	createUndoElement(currentElement_, 1, 0);
	if (chord->removeNote(note, stemPolicy_)) {
		reconnectDeletedTies(note);
		return true;
	}
	deleteLastUndo();
	return false;
}



bool NVoice::deleteAtPosition(int y) {
	int line;
	bool ok = false;
	NNote *note;

	if (!currentElement_) return false;

	createUndoElement(currentElement_, 1, 0);
	if (y < theStaff_->staff_props_.base) {
		line = 8 - 2 * (y-2 - theStaff_->staff_props_.base) / LINE_DIST;
	}
	else {
		line = 8 - 2 * (y+1 - theStaff_->staff_props_.base) / LINE_DIST;
	}
	note = currentElement_->searchLine(line, 2);
	if (note) {
		ok = currentElement_->deleteNoteAtLine(line, stemPolicy_);
		reconnectDeletedTies(note);
	}
	else {
		deleteLastUndo();
	}
	return ok;
}

/*------------------------- insertion due to user interaction --------------------*/


void NVoice::insertTmpElemAtPosition(int xpos, NMusElement *tmpElem) {
	NMusElement *elem;
	bool found;
	int idx;

	tmpElem->setActual(true);
	tmpElem->setStaffProps(&(theStaff_->staff_props_));
	if (musElementList_.isEmpty()) {
		musElementList_.append(tmpElem);
		createUndoElement(musElementList_.at(), 0, 1);
		currentElement_ = musElementList_.first();
		return;
	}
	if (currentElement_) {
		currentElement_->setActual(false);
	}
	found = false;
	elem = musElementList_.first();
	while (!found  && elem != 0) {
		if (xpos > elem->getBbox()->x()) {
			elem = musElementList_.next();
		}
		else {
			found = true;
			idx = musElementList_.at();
		}
	}
	switch (tmpElem->getType()) {
		case T_KEYSIG: ((NKeySig *) tmpElem)->setClef(&(theStaff_->actualClef_));
				break;
	}
	if (!found) {
		musElementList_.append(tmpElem);
	}
	else {
		musElementList_.insert(idx, tmpElem);
	}
	currentElement_ = tmpElem;
	createUndoElement(currentElement_, 0, 1);
}

#ifdef XXX
int NVoice::quant(int l, int *dotcount) {
	unsigned int testlength;
	unsigned int deltamin3 = (1<<30), deltamin9 = (1<<30);
	int i, j;
	*dotcount = 0;

	if (l > DOUBLE_WHOLE_LENGTH) return DOUBLE_WHOLE_LENGTH;

	testlength = (0x3 << 8);
	for (i = 8; i > 0; i--) {
		if (testlength > (unsigned int) l) {
			testlength >>= 1;
		}
		else {
			deltamin3 = l - testlength;
			break;
		}
	}

	testlength = (0x9 << 7);
	for (j = 8; j > 0; j--) {
		if (testlength > (unsigned int) l) {
			testlength >>= 1;
		}
		else {
			deltamin9 = l - testlength;
			break;
		}
	}

	if (deltamin9 < deltamin3) {
		*dotcount = 1;
		return (0x3 << j);
	}
	return (0x3 << i);
}
#else
int NVoice::quant(int l, int *dotcount, int maxlength) {
	unsigned int testlength;
	unsigned int deltamin3 = (1<<30), deltamin9 = (1<<30);
	int i, j,  shifts;
	int ret;
	*dotcount = 0;

	if (l > maxlength) return maxlength;

	maxlength /= MULTIPLICATOR / 3;
	l /= MULTIPLICATOR / 3;
	for (shifts = 0; shifts < 9 && (0x3 << shifts) <  maxlength; shifts++);

	testlength = (0x3 << shifts);
	for (i = shifts; i > 0; i--) {
		if (testlength > (unsigned int) l) {
			testlength >>= 1;
		}
		else {
			deltamin3 = l - testlength;
			break;
		}
	}

	testlength = (0x9 << (shifts - 1));
	for (j = shifts; j > 0; j--) {
		if (testlength > (unsigned int) l) {
			testlength >>= 1;
		}
		else {
			deltamin9 = l - testlength;
			break;
		}
	}

	if (deltamin9 < deltamin3) {
		*dotcount = 1;
		ret = (MULTIPLICATOR << j);
		return ret;
	}
	ret = (MULTIPLICATOR << i);
	return ret;
}
#endif

void NVoice::collectAndInsertPlayable(QList<NMusElement> *patterns, int targetLength, bool useExistingElement) {
	int len, restlen;
	bool isChord;
	int dotcount;
	int akpos;
	NMusElement *elem2, *lastPattern;
	QList<NNote> *noteList;
	NNote *note;

	if (patterns->isEmpty()) {
		NResource::abort("internal error: collectAndInsertPlayable: isEmpty()");
	}
	lastPattern = patterns->last();
	isChord = lastPattern->getType() == T_CHORD;
	while (patterns->count() > 1) {
		if ((akpos = musElementList_.find(patterns->first())) == -1) {
			NResource::abort("internal error: collectAndInsertPlayable: find == -1 (1)");
		}
		musElementList_.remove();
		patterns->remove();
	}
	if ((akpos = musElementList_.find(lastPattern)) == -1) {
		NResource::abort("internal error: collectAndInsertPlayable: find == -1 (2)");
	}
	patterns->remove();
	if (!patterns->isEmpty()) {
		NResource::abort("internal error: collectAndInsertPlayable: patterns != empty");
	}

	if (targetLength < MULTIPLICATOR && useExistingElement) {
		musElementList_.remove();
		musElementList_.at(akpos-1);
		return;
	}

	while (targetLength > MULTIPLICATOR) {
	        len = quant(targetLength, &dotcount, isChord ? DOUBLE_WHOLE_LENGTH : WHOLE_LENGTH);
		restlen  = targetLength - (dotcount ? 3 * len / 2 : len);
		if (restlen > MULTIPLICATOR || !useExistingElement) {
	     		elem2 = ((NChord *) lastPattern)->clone();
		}
		else {
			elem2 = (NChord *) lastPattern;
		}
	        elem2->changeLength(len);
	        elem2->setDotted(dotcount);
		if (restlen > MULTIPLICATOR || !useExistingElement) {
			if (isChord) {
				noteList = elem2->getNoteList();
				for (note = noteList->first(); note; note = noteList->next()) {
					note->status |= STAT_TIED;
				}
			}
			musElementList_.insert(akpos, elem2);
			if (isChord) {
				for (note = noteList->first(); note; note = noteList->next()) {
					reconnectTies(note);
				}
				for (note = noteList->first(); note; note = noteList->next()) {
					findTieMember(note);
				}
			}
		}
		akpos++;
		targetLength -= elem2->getMidiLength();
	}
	if (musElementList_.find(lastPattern) == -1) {
		NResource::abort("internal error: collectAndInsertPlayable: find == -1 (3)");
	}
	
}

void NVoice::autoBar() {
	int akpos, idxOfFirstBar, barpos;
	int ticks, maxticks;
	bool foundfirstBar = false;
	bool barInserted = false;
	bool go_on;
	int lrest, len1, len2;
	NTimeSig *timesig;
	NRest *rest;
	NMusElement *elem, *nextElem;
	QList <NMusElement> elems;

	createUndoElement(0, musElementList_.count(), 0);

	ticks = 0;
	go_on = true;
	for (elem = musElementList_.last(); elem && go_on; elem = musElementList_.prev()) {
		switch (elem->getType()) {
			case T_REST: ticks += elem->getSubType(); break;
			case T_CHORD: go_on = false; break;
			default: break;
		}
	}
	if (ticks < 2*MULTIPLICATOR) {
		musElementList_.append(rest = new NRest(main_props_, &(theStaff_->staff_props_), &yRestOffs_, WHOLE_LENGTH, 0));
		rest->midiTime_ = midiEndTime_ + WHOLE_LENGTH;
		musElementList_.append(rest = new NRest(main_props_, &(theStaff_->staff_props_), &yRestOffs_, WHOLE_LENGTH, 0));
		rest->midiTime_ = midiEndTime_ + 2*WHOLE_LENGTH;
	}

	elem = musElementList_.first();
	while (elem) {
		if (elem->getType() == T_SIGN && elem->getSubType() == SIMPLE_BAR) {
			if (foundfirstBar) {
				elem = musElementList_.next();
				if (!elem) break;
				if (elem->getType() != T_SIGN || ((elem->getSubType() | ( SPECIAL_ENDING1 | SPECIAL_ENDING2 )) == 0)) {
					musElementList_.prev();
					musElementList_.remove();
					elem = musElementList_.current();
				}
			}
			else {
				idxOfFirstBar = musElementList_.at();
				foundfirstBar = true;
				elem = musElementList_.next();
			}
		}
		else {
			elem = musElementList_.next();
		}
	}

	ticks = 0;
	timesig = getFirstTimeSig();
	if (!timesig) {
		maxticks = WHOLE_LENGTH;
	}
	else {
		maxticks = MULTIPLICATOR*timesig->numOf128th();
	}
	if (foundfirstBar) {
		elem = musElementList_.at(idxOfFirstBar + 1);
		if (!elem) {
			elem = musElementList_.first();
		}
	}
	else {
		elem = musElementList_.first();
	}
	for (; elem; elem = musElementList_.next()) {
		akpos = musElementList_.at();
		switch (elem->getType()) {
			case T_TIMESIG: maxticks = MULTIPLICATOR*((NTimeSig *) elem)->numOf128th();
					continue;
			case T_SIGN:
				 if (elem->getSubType() & 
				((SIMPLE_BAR | REPEAT_OPEN | REPEAT_CLOSE | REPEAT_OPEN_CLOSE | SPECIAL_ENDING1 | SPECIAL_ENDING2))){
					ticks = 0;
					continue;
				 }
		}
		if (elem->getType() & PLAYABLE) {
			ticks += elem->getMidiLength();
		}
		if (ticks == maxticks) {
			ticks = 0;
			nextElem = musElementList_.next();
			 if (nextElem && nextElem->getType() == T_SIGN && (nextElem->getSubType() & 
				(SIMPLE_BAR | REPEAT_OPEN | REPEAT_CLOSE | REPEAT_OPEN_CLOSE | SPECIAL_ENDING1 | SPECIAL_ENDING2))){
				continue;
			 }
			 musElementList_.insert(akpos+1, new NSign(main_props_, &(theStaff_->staff_props_), SIMPLE_BAR));
		}
		else if (ticks > maxticks) {
		   	akpos = musElementList_.at();
			switch (elem->getType()) {
				case T_CHORD: 
				case T_REST: 
					     len2 = ticks - maxticks;
					     len1 = elem->getMidiLength() - len2;
					     elems.append(elem);
					     collectAndInsertPlayable(&elems, len1, false);
					     akpos = musElementList_.at();
					     musElementList_.insert(akpos, new NSign(main_props_, &(theStaff_->staff_props_), SIMPLE_BAR));
					     barpos = akpos;
					     elems.append(elem);
					     collectAndInsertPlayable(&elems, len2, true);
					     barInserted = true;
					     break;
			}
			ticks = 0;	
			elem = musElementList_.at(barpos);
		}
	}
	if (!barInserted) {
		return;
	}
	elem = musElementList_.last();
	while (elem && !(elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS))) {
		musElementList_.remove();
		elem = musElementList_.last();
	}
	elem = musElementList_.first();
	lrest = 0;
	while (elem) {
		if (elem->getType() == T_REST) {
			elems.append(elem);
			lrest += elem->getMidiLength();
		}
		else if (elem->getType() == T_CHORD  || 
		    elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
			if (lrest > MULTIPLICATOR) {
				collectAndInsertPlayable(&elems, lrest, true);
			}
			lrest = 0;
		}
		elem = musElementList_.next();
	}
	go_on = true;
	idxOfFirstBar = -1;
	for (elem = musElementList_.last(); elem && (elem->getType() != T_REST || elem->midiTime_ > midiEndTime_) && go_on; elem = musElementList_.prev()) {
		switch(elem->getType()) {
			case T_SIGN: if ((elem->getSubType() & BAR_SYMS) == 0) break;
				     idxOfFirstBar = musElementList_.at();
				     break;
			case T_REST: break;
			default: go_on = false;
		}
	}
	if (idxOfFirstBar != -1) {
		elem = musElementList_.last();
		while (elem && musElementList_.at() > idxOfFirstBar) {
			delete elem;
			musElementList_.remove();
			elem = musElementList_.last();
		}
	}
	setCountOfAddedItems(musElementList_.count());
}

void NVoice::autoBarVoice123andSoOn() {
	NMusElement *elem, *specialElement;
	int specialElemTime;
        int barpos, akpos, len1, len2;
	QList <NMusElement> elems;

	createUndoElement(0, musElementList_.count(), 0);
	elem = musElementList_.first();
	if (!elem) return;
	theStaff_->syncSpecialElement(elem->getXpos());
	for (; elem; elem = musElementList_.next()) {
		while (specialElement = theStaff_->checkSpecialElement(elem->getXpos())) {
			if (specialElement->getType() == T_SIGN && ((specialElement->getSubType() & BAR_SYMS) != 0)) {
				specialElemTime = specialElement->midiTime_;
				if (specialElemTime > elem->midiTime_ && specialElemTime < elem->midiTime_ + elem->getMidiLength()) {
					akpos = musElementList_.at();
					switch (elem->getType()) {
					case T_CHORD: 
					case T_REST: 
					     len2 = elem->midiTime_ + elem->getMidiLength() - specialElemTime;
					     len1 = elem->getMidiLength() - len2;
					     elems.append(elem);
					     collectAndInsertPlayable(&elems, len1, false);
					     akpos = musElementList_.at();
					     barpos = akpos;
					     elems.append(elem);
					     collectAndInsertPlayable(&elems, len2, true);
					     break;
					}
					elem = musElementList_.at(barpos);
				}
			}
		}
	}
	setCountOfAddedItems(musElementList_.count());
}

void NVoice::autoBeam(int count, bool includeRests) {
	NMusElement *elem;
	QList<NChord> *beamlist;
	int status = 0;

	beamlist = new QList<NChord>();
	createUndoElement(0, musElementList_.count(), 0);
	if (!firstVoice_) {
		elem = musElementList_.first();
		if (elem) {
			theStaff_->syncSpecialElement(elem->getXpos());
		}
	}

	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		if (!firstVoice_) {
			 if (theStaff_->checkSpecialElement(elem->getXpos())) {
				 while (theStaff_->checkSpecialElement(elem->getXpos()));
				 if (beamlist->count() > 1) {
					NChord::computeBeames(beamlist, stemPolicy_);
					beamlist = new QList<NChord>();
				 }
				 else {
					beamlist->clear();
				 }
			}
		}
		switch (elem->getType()) {
			case T_CHORD:
				if (elem->getSubType() <= NOTE8_LENGTH) {
					if (beamlist->count() >= count || (beamlist->count() > 0 && ((elem->status_ & STAT_GRACE) != status))) {
						NChord::computeBeames(beamlist, stemPolicy_);
						beamlist = new QList<NChord>();
						status = elem->status_ & STAT_GRACE;
					}
					beamlist->append((NChord *)elem);
				}
				else {
					if (beamlist->count() > 1) {
						NChord::computeBeames(beamlist, stemPolicy_);
						beamlist = new QList<NChord>();
					}
					else {
						beamlist->clear();
					}
				}
				break;
			case T_SIGN:
				if (elem->getSubType() & BAR_SYMS) {
					if (beamlist->count() > 1) {
						NChord::computeBeames(beamlist, stemPolicy_);
						beamlist = new QList<NChord>();
					}
					else {
						beamlist->clear();
					}
				}
				break;
			case T_REST:
				if (includeRests) break;
				if (beamlist->count() > 1) {
					NChord::computeBeames(beamlist, stemPolicy_);
					beamlist = new QList<NChord>();
				}
				else {
					beamlist->clear();
				}
				break;
		}
	}
	if (beamlist->count() > 1) {
		NChord::computeBeames(beamlist, stemPolicy_);
		beamlist = new QList<NChord>();
	}
	else {
		beamlist->clear();
		delete beamlist;
	}
}

void NVoice::eliminateRests(QList<NMusElement> *foundRests, int restSum, int over, NChord *lastChord) {
	QList<NMusElement> elems;
	int len1;

	if (lastChord->status_ & STAT_BEAMED) lastChord->breakBeames();
	len1 = lastChord->getMidiLength() + over;
	elems.append(lastChord);
	collectAndInsertPlayable(&elems, len1, true);
	collectAndInsertPlayable(foundRests, restSum - over, true);
}

void NVoice::cleanupRests(int shortestRest, bool region) {
	//int x0, x1, idx;
	NChord* lastChord = 0;
	NMusElement *elem, *stop_elem;
	QList<NMusElement> foundRests;
	int restSum = 0;
	int over;
	int xpos0 = -1, xpos1 = -1;
	int idx0 = -1, idx1 = -1;

        if (region) {
	   if (startElement_ && endElement_) {
		if (endElementIdx_ > startElemIdx_) {
			xpos0 = startElement_->getXpos();
			xpos1 = endElement_->getXpos();
			idx0 = startElemIdx_;
			idx1 = endElementIdx_;
		}
		else {
			xpos0 = endElement_->getXpos();
			xpos1 = startElement_->getXpos();
			idx0 = endElementIdx_;
			idx1 = startElemIdx_;
		}
		if ((elem = musElementList_.at(idx0)) == 0) {
			 NResource::abort(" NVoice::setHalfsTo: internal error", 1);
		}
		createUndoElement(idx0, idx1 - idx0 + 1, 0);
	   }
	   else {
		elem = musElementList_.first();
		createUndoElement(0, musElementList_.count(), 0);
	   }
	}
	else {
		elem = musElementList_.first();
		createUndoElement(0, musElementList_.count(), 0);
	}


        for (;elem && (idx0 <= idx1 || xpos1 == -1); elem = musElementList_.next(), idx0++) {
		switch(elem->getType()) {
			case T_CHORD: 
				     if ((over = (restSum % shortestRest)) && lastChord) {
					eliminateRests(&foundRests, restSum, over, lastChord);
					if (musElementList_.find(lastChord) == -1) {
						NResource::abort("internal error: cleanupRests: chord not found");
					}
				     }
				     while (!foundRests.isEmpty()) {
					foundRests.first();
					foundRests.remove();
				     }
				     restSum = 0;
				     lastChord = (NChord *) elem;
				     break;
			case T_SIGN: if (elem->getSubType() & BAR_SYMS) {
					if ((over = (restSum % shortestRest)) && lastChord) {
                                     		eliminateRests(&foundRests, restSum, over , lastChord);
						if (musElementList_.find(lastChord) == -1) {
							NResource::abort("internal error: cleanupRests: chord not found");
						}
					}
					foundRests.clear();
					restSum = 0;
					lastChord = 0;
				     }
				     break;
			case T_REST: restSum += elem->getMidiLength(); 
				     foundRests.append(elem);
				     break;
		}
	}
	
}

int NVoice::searchPositionAndUpdateSigns(int dest_xpos, NMusElement **elem, bool *found, NMusElement **elem_before /* = 0 */,
					int *countof128th /* = 0 */, int *lastbaridx  /* = 0 */, int *lastbarpos /* = 0 */, 
					int *lastbartime /* = 0 */) {
	*found = false;
	*elem = 0;
	if (lastbaridx) *lastbaridx = 0;
	if (lastbarpos) *lastbarpos = 0;
	if (lastbartime) *lastbartime = 0;
	if (elem_before) *elem_before = 0;
	if (countof128th) *countof128th = 128;
	if (musElementList_.count() < 1) {
		return -1;
	}
	*elem = musElementList_.first();
	while ((*elem) && !(*found)) {
		*found = (*elem)->getBbox()->x() >= dest_xpos;
		if (!(*found)) { 
			switch ((*elem)->getType()) {
			case T_CLEF:
				theStaff_->actualClef_.change((NClef *) (*elem));
				break;
			case T_SIGN:
				if (!((*elem)->getSubType() & BAR_SYMS)) break;
				if (lastbarpos) *lastbarpos = (*elem)->getXpos();
				if (lastbaridx) *lastbaridx = musElementList_.at();
				if (lastbartime) *lastbartime = (*elem)->midiTime_;
				break;
			case T_KEYSIG:
				theStaff_->actualKeysig_.change((NKeySig *) (*elem));
				break;
			case T_TIMESIG:
				if (countof128th) *countof128th = ((NTimeSig *) (*elem))->numOf128th();
				break;
			}
			if (elem_before) *elem_before = *elem;
			*elem = musElementList_.next();
		}
	}
	if (*found) {
		return musElementList_.at();
	}
	*elem = musElementList_.last();
	return musElementList_.at();
}

void NVoice::searchPositionAndUpdateTimesig(int dest_xpos, int *countof128th) {
	bool found = false;
	NMusElement *elem;
	*countof128th = 128;
	if (musElementList_.count() < 1) {
		return;
	}
	elem = musElementList_.first();
	while (elem && !found) {
		found = elem->getBbox()->x() >= dest_xpos;
		if (!found) { 
			if (elem->getType() == T_TIMESIG) *countof128th = ((NTimeSig *) elem)->numOf128th();
			elem = musElementList_.next();
		}
	}
}

int NVoice::validateKeysig(int lastbaridx, int insertpos) {
	NMusElement *elem;
	QList<NNote> *noteList;
	NNote *note;
	int lastbarpos;
	bool found;

	if (lastbaridx < 0) {
		searchPositionAndUpdateSigns(insertpos, &elem, &found, 0, 0, &lastbaridx, &lastbarpos);
	}
	else {
		elem = musElementList_.at(lastbaridx);
		lastbarpos = elem->getXpos();
	}
	theStaff_->actualKeysig_.resetAtBar();
	for (;elem && elem->getBbox()->x() < insertpos; elem = musElementList_.next()) {
		if (elem->getType() != T_CHORD) continue;
		((NChord *) elem)->accumulateAccidentals(&(theStaff_->actualKeysig_));
	}
	return lastbarpos;
}

void NVoice::validateKeysigAccordingPos(int lastbarpos, int insertpos) {
	NMusElement *elem;
	bool found;

	searchPositionAndUpdateSigns(insertpos, &elem, &found);
	if (!found) return;

	for (;elem && insertpos > elem->getBbox()->x(); elem = musElementList_.next()) {
		if (elem->getType() != T_CHORD) continue;
		((NChord *) elem)->accumulateAccidentals(&(theStaff_->actualKeysig_));
	}
}

void NVoice::setCorrectClefAccordingTime(int miditime) {
	int oldidx;
	NMusElement *elem;

	oldidx = musElementList_.at();
	theStaff_->actualClef_.change(NResource::nullClef_);
	for (elem = musElementList_.first(); elem && elem->midiTime_ <= miditime; elem = musElementList_.next()) {
		if (elem->getType() == T_CLEF) {
			theStaff_->actualClef_.change((NClef *) elem);
		}
	}

	if (oldidx >= 0) musElementList_.at(oldidx);
}



int NVoice::findLastBarTime(int xpos) {
	int lastbartime = 0;
	NMusElement *elem;
	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		if (elem->getXpos() >= xpos) break;
		if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) lastbartime = elem->midiTime_;
	}
	
	return lastbartime;
}


void NVoice::insertAtPosition(int el_type, int xpos, int line, int sub_type, int offs, NMusElement *tmpElem) {
	NMusElement *new_elem, *elem_before, *elem;
	bool found, is_chord = false;
	unsigned int status = 0;
	unsigned int status2 = 0;
	int idx, idx2;
	int lastbaridx = 0;
	int countof128th = 128;
	int dotcount;
	int diff_total, len, len2, lastElemTime;
	NRest *rest;
	NNote *part;
	NMusElement *startElement = 0;
	int newcount = 0;

	if (currentElement_) {
		currentElement_->setActual(false);
	}
	if (!firstVoice_) {
		theStaff_->searchPositionAndUpdateTimesig(xpos, &countof128th);
		idx = searchPositionAndUpdateSigns(xpos, &elem, &found, &elem_before);
	}
	else {
		idx = searchPositionAndUpdateSigns(xpos, &elem, &found, &elem_before, &countof128th, &lastbaridx);
	}
	if (elem_before && found) {
		if ((elem_before->status_ & STAT_BEAMED) && (elem->status_ & STAT_BEAMED)) {
			if (((NChord *) elem_before)->getBeamList() == ((NChord *) elem)->getBeamList()) {
				currentElement_ =musElementList_.prev();
				breakBeames();
				musElementList_.at(idx);
			}
		}
		if ((elem_before->status_ & STAT_TUPLET) && (elem->status_ & STAT_TUPLET)) {
			if (elem_before->getTupletList() == elem->getTupletList()) {
				currentElement_ = musElementList_.prev();
				breakTuplet();
				musElementList_.at(idx);
			}
		}
	}
	if (!firstVoice_) {
		lastElemTime = elem_before ? elem_before->midiTime_ + elem_before->getMidiLength() : 0;
		diff_total = theStaff_->findLastBarTime(xpos) - lastElemTime;
		if (diff_total > 0) {
			len = diff_total % countof128th;
			if (len > 0) {
				len = countof128th - len;
				diff_total -= len;
				while (len >= MULTIPLICATOR) {
					len2 = quant(MULTIPLICATOR*len, &dotcount, WHOLE_LENGTH);
					len -= dotcount ? 3 * len2 / 2 : len2;
					diff_total -= dotcount ? 3 * len2 / 2 : len2;
					status = STAT_HIDDEN;
					if (dotcount) status |= STAT_SINGLE_DOT;
					rest = new NRest(main_props_, theStaff_->getStaffPropsAddr(), &yRestOffs_, len2, status); 
					if (!startElement) startElement = rest;
					newcount++;
					if (found) {
						musElementList_.insert(idx++, rest);
					}
					else {
						musElementList_.append(rest);
					}
				}
			}
			while (diff_total > 0) {
				len2 = quant(MULTIPLICATOR*countof128th, &dotcount, WHOLE_LENGTH);
				diff_total -= dotcount ? 3 * len2 / 2 : len2;
				status = STAT_HIDDEN;
				if (dotcount) status |= STAT_SINGLE_DOT;
				rest = new NRest(main_props_, theStaff_->getStaffPropsAddr(), &yRestOffs_, len2, status); 
				if (!startElement) startElement = rest;
				newcount++;
				if (found) {
					musElementList_.insert(idx++, rest);
				}
				else {
					musElementList_.append(rest);
				}
			}
		}
	}
	switch (el_type) {
		case T_CHORD:
			is_chord = true;
			status = STAT_FORCE;
			if (offs == UNDEFINED_OFFS) {
				if (found) {
					idx2 = musElementList_.at();
				}
				else {
					idx2 = musElementList_.count() - 1;
				}
				if (idx2 >= 0) {
					theStaff_->validateKeysig(firstVoice_ ? lastbaridx : -1, xpos);
					offs = theStaff_->actualKeysig_.computeOffs(line);
				}
				else {
					offs = 0;
				}
				status = (unsigned int) 0;
			}
			if (main_props_->tied) status |= STAT_TIED;
			if (main_props_->staccato) status |= STAT_STACC;
			if (main_props_->sforzato) status |= STAT_SFORZ;
			if (main_props_->portato) status |= STAT_PORTA;
			if (main_props_->strong_pizzicato) status |= STAT_STPIZ;
			if (main_props_->sforzando) status |= STAT_SFZND;
			if (main_props_->fermate) status |= STAT_FERMT;
			if (main_props_->grace) status |= STAT_GRACE;
			if (main_props_->arpeggio) status |= STAT_ARPEGG;
			status |= (main_props_->dotcount & DOT_MASK);
			status |= (main_props_->noteBody & BODY_MASK);
			if (main_props_->pedal_on) status2 |= STAT2_PEDAL_ON;
			if (main_props_->pedal_off) status2 |= STAT2_PEDAL_OFF;
			new_elem = 
			new NChord(main_props_, &(theStaff_->staff_props_), line,  offs, main_props_->actualLength, stemPolicy_, status, status2);
				part = new_elem->getNoteList()->first();
		break;
		case T_REST:
			status = main_props_->dotcount | (main_props_->hidden ? STAT_HIDDEN : 0);
			new_elem = 
			new NRest(main_props_, &(theStaff_->staff_props_), &yRestOffs_, sub_type, status);
		break;
		case T_SIGN:
			new_elem =
			new NSign(main_props_, &(theStaff_->staff_props_), sub_type);
			break;
		case T_CLEF:
			new_elem = tmpElem;
			break;
		default: NResource::abort("unknown music element");
	}
	new_elem->setActual(true);
	currentElement_ = new_elem;
	if (musElementList_.isEmpty()) {
		if (!startElement) startElement = new_elem;
		newcount++;
		musElementList_.append(new_elem);
		createUndoElement(startElement, 0, newcount);
		musElementList_.first();
		if (is_chord) {
			reconnectTies(part);
		}
		if (is_chord && main_props_->tied) {
			findTieMember(part);
		}
		if (is_chord && NResource::allowInsertEcho_) {
			NResource::mapper_->playImmediately(&(theStaff_->actualClef_), (NChord *) new_elem,
			theStaff_->getVoice(), theStaff_->getChannel(), theStaff_->getVolume(), theStaff_->transpose_);
		}
		return;
	}
	if (!startElement) startElement = new_elem;
	newcount++;
	if (!found) {
		musElementList_.append(new_elem);
	}
	else {
		musElementList_.insert(idx, new_elem);
	}
	createUndoElement(startElement, 0, newcount);
	if (is_chord) {
		reconnectTies(part);
	}
	if (is_chord && main_props_->tied) {
		findTieMember(part);
	}
	if (is_chord && NResource::allowInsertEcho_) {
		NResource::mapper_->playImmediately(&(theStaff_->actualClef_), (NChord *) new_elem,
		theStaff_->getVoice(), theStaff_->getChannel(), theStaff_->getVolume(), theStaff_->transpose_);
	}
}

bool NVoice::insertNewNoteAt(int line, QPoint p, int offs) {
	int lastbaridx = 0;
	int lastbarpos = 0;
	bool found = false;
	unsigned int status = STAT_FORCE;
	NMusElement *elem;
	NNote *note;

	if (currentElement_) {
		currentElement_->setActual(false);
	}
	
	elem = musElementList_.first();
	while (!found  && elem != 0) {
		switch (elem->intersects_horizontally(p)) {
			case 0: found = true; break;
			case -1: return false;
			default: 
			   switch (elem->getType()) {
				case T_KEYSIG:
					theStaff_->actualKeysig_.change((NKeySig *) elem);
					break;
				case T_SIGN:
					if (elem->getSubType() & BAR_SYMS) {
						lastbaridx = musElementList_.at();
						lastbarpos = elem->getXpos();
					}
					break;
				 case T_CLEF:
					theStaff_->actualClef_.change((NClef *) elem);
					break;

			   }
			   elem = musElementList_.next();
		}
	}
	if (!found) {
		return false;
	}
	if (offs == UNDEFINED_OFFS) {
		theStaff_->validateKeysig(firstVoice_ ? lastbaridx : -1, elem->getBbox()->x());
		offs = theStaff_->actualKeysig_.computeOffs(line);
		status &= (~STAT_FORCE);
	}
	currentElement_ = elem;
	createUndoElement(currentElement_, 1, 0);
	if (main_props_->tied) status |= STAT_TIED;
	status |= main_props_->noteBody;
	note = currentElement_->insertNewNote(line, offs, stemPolicy_, status);
	if (note) {
		reconnectTies(note);
		if (main_props_->tied) {
			findTieMember(note);
		}
	}
	else {
		deleteLastUndo();
	}
	if (note && NResource::allowInsertEcho_) {
		NResource::mapper_->playImmediately(&(theStaff_->actualClef_), (NChord *) elem,
		theStaff_->getVoice(), theStaff_->getChannel(), theStaff_->getVolume(), theStaff_->transpose_);
	}
	if (currentElement_) {
		currentElement_->setActual(true);
	}
	return true;
}

bool NVoice::insertNewNoteAtCurrent(int line, int offs) {
	int lastbaridx = 0;
	bool found = false;
	unsigned int status = STAT_FORCE;
	NMusElement *elem;
	NNote *note;

	if (!currentElement_)  return false;
	
	elem = musElementList_.first();
	while (!found  && elem != 0) {
		if (!(found = elem == currentElement_)) {
			switch (elem->getType()) {
				case T_KEYSIG:
					theStaff_->actualKeysig_.change((NKeySig *) elem);
					break;
				case T_SIGN:
					if (elem->getSubType() & BAR_SYMS) {
						lastbaridx = musElementList_.at();
					}
					break;
				 case T_CLEF:
					theStaff_->actualClef_.change((NClef *) elem);
					break;

			}
			elem = musElementList_.next();
		}
	}
	if (!found) {
		NResource::abort("insertNewNoteAtCurrent: internal error");
	}
	if (offs == UNDEFINED_OFFS) {
		validateKeysig(lastbaridx, musElementList_.at());
		theStaff_->validateKeysig(lastbaridx, elem->getBbox()->x());
		offs = theStaff_->actualKeysig_.computeOffs(line);
		status &= (~STAT_FORCE);
	}
	currentElement_ = elem;
	createUndoElement(currentElement_, 1, 0);
	if (main_props_->tied) status |= STAT_TIED;
	note = currentElement_->insertNewNote(line, offs, stemPolicy_, status);
	if (note) {
		reconnectTies(note);
		if (main_props_->tied) {
			findTieMember(note);
		}
	}
	else {
		deleteLastUndo();
	}
	if (note && NResource::allowInsertEcho_) {
		NResource::mapper_->playImmediately(&(theStaff_->actualClef_), (NChord *) elem,
		theStaff_->getVoice(), theStaff_->getChannel(), theStaff_->getVolume(), theStaff_->transpose_);
	}
	return true;
}

void NVoice::insertAfterCurrent(int el_type, int subtype) {
	int idx;
	NMusElement *new_elem;
	if (!currentElement_) return;
	
	switch (el_type) {
		case T_SIGN: new_elem = new NSign(main_props_, &(theStaff_->staff_props_), subtype);
				break;
		default: return;
	}
	currentElement_->setActual(false);
	if (musElementList_.find(currentElement_) == -1) {
		NResource::abort("insertAfterCurrent: internal error");
	}
	if (musElementList_.next()) {
		idx = musElementList_.at();
		musElementList_.insert(idx, new_elem);
	}
	else {
		musElementList_.append(new_elem);
	}
	currentElement_ = musElementList_.current();
	createUndoElement(musElementList_.at(), 0, 1);
	currentElement_->setActual(true);
}

bool NVoice::insertAfterCurrent(NMusElement *elem) {
	int idx;
	bool is_chord = false;
	NNote *note;
	if (!currentElement_) return false;
	if (musElementList_.find(currentElement_) == -1) {
		NResource::abort("insertAfterCurrent: internal error");
	}
	if (elem->getType() == T_CHORD) {
		is_chord = true;
		note = elem->getNoteList()->first();
	}
	if (currentElement_) currentElement_->setActual(false);
	if (musElementList_.next()) {
		idx = musElementList_.at();
		musElementList_.insert(idx, elem);
	}
	else {
		musElementList_.append(elem);
	}
	currentElement_ = musElementList_.current();
	createUndoElement(musElementList_.at(), 0, 1);
	if (is_chord) {
		reconnectTies(note);
	}
	if (is_chord && (note->status & STAT_TIED)) {
		findTieMember(note);
	}
	currentElement_->setActual(true);
	return true;
}

void NVoice::insertBarAt(int xpos) {
	NSign *new_elem;
	NMusElement *elem;
	bool found;
	int idx;
	new_elem = new NSign(main_props_, &(theStaff_->staff_props_), SIMPLE_BAR);
	found = false;
	elem = musElementList_.first();
	while (!found  && elem != 0) {
		if (xpos > elem->getBbox()->x()) {
			elem = musElementList_.next();
		}
		else {
			found = true;
			idx = musElementList_.at()-1;
		}
	}
	if (!found) {
		musElementList_.append(new_elem);
	}
	else {
		musElementList_.insert(idx, new_elem);
	}
	if (currentElement_) currentElement_->setActual(true);
	currentElement_ = new_elem;
	currentElement_->setActual(true);
}

/*------------------------ playing voice -------------------------------------*/


int NVoice::getMidiTime() const {
	if (currentElement_) {
		return currentElement_->midiTime_;
	}
	return 0;
}

void NVoice::getTempoSigs(NTempoTrack *ttrack, int startTime) {
	NMusElement *elem;
	int actualTempo = DEFAULT_TEMPO;
	NSign *newsign, *sign;
	NChord *chord;
	int ending1Time;
	bool found2ndCoda = false;

	repeatIdx_ = 0;
	repeatTime_ = 0;
	endingIdx_ = -1;
	segnoIdx_ = -1;
	codaStatus_ = -1;
	idxOf2ndCodaSign_ = -2;
	repeatCount_ = 1;
	theStaff_->timeOffset_ = 0;

	for (elem = musElementList_.first(); !found2ndCoda && elem; elem = musElementList_.next()) {
		if (elem->getType() != T_SIGN) continue;
		if (elem->getSubType() != CODA) continue;
		switch (idxOf2ndCodaSign_) {
			case -2: idxOf2ndCodaSign_ = -1; break;
			case -1: idxOf2ndCodaSign_ = musElementList_.at(); timeOf2ndCoda_ = elem->midiTime_; found2ndCoda = true; break;
		}
	}

	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		if (elem->getType() == T_SIGN) {
			switch(elem->getSubType()) {
				case TEMPO_SIGNATURE: sign = (NSign *) elem;
						      actualTempo = sign->getTempo();
						      newsign = new NSign(&NResource::nullMainProps_, &NResource::nullprops_, TEMPO_SIGNATURE);
						      newsign->setRealMidiTime(sign->midiTime_ + theStaff_->timeOffset_);
						      newsign->setTempo(actualTempo);
						      ttrack->insertTempoSign(newsign);
						break;
				case ACCELERANDO: newsign = new NSign(&NResource::nullMainProps_, &NResource::nullprops_, ACCELERANDO);
						      newsign->setRealMidiTime(elem->midiTime_ + theStaff_->timeOffset_);
						      ttrack->insertTempoSign(newsign);
						break;
				case RITARDANDO: newsign = new NSign(&NResource::nullMainProps_, &NResource::nullprops_, RITARDANDO);
						      newsign->setRealMidiTime(elem->midiTime_ + theStaff_->timeOffset_);
						      ttrack->insertTempoSign(newsign);
						break;
				case REPEAT_OPEN: repeatIdx_ = musElementList_.at(); 
						  repeatTime_ = elem->midiTime_;
						  break;
				case REPEAT_CLOSE: if (repeatIdx_ >= 0) {
						  	if (startTime <=  elem->midiTime_) theStaff_->timeOffset_ += elem->midiTime_ - repeatTime_;
							if (repeatCount_ == ((NSign *) elem)->getRepeatCount() - 1)  {
								endingIdx_ = musElementList_.at();
							}
						  	if (++repeatCount_ < ((NSign *) elem)->getRepeatCount()) {
								musElementList_.at(repeatIdx_);
								break;
							}
							musElementList_.at(repeatIdx_);
							repeatIdx_ = -1;
							repeatCount_ = 1;
						  }
						  else {
							endingIdx_ = -1;
						  }
						  break;
				case REPEAT_OPEN_CLOSE:
						  
						  if (repeatIdx_ >= 0) {
							endingIdx_ = musElementList_.at();
						  	if (startTime <=  elem->midiTime_) theStaff_->timeOffset_ += elem->midiTime_ - repeatTime_;
							musElementList_.at(repeatIdx_);
							repeatIdx_ = -1;
						  }
						  else {
							endingIdx_ = -1;
							repeatIdx_ = musElementList_.at(); 
							repeatTime_ = elem->midiTime_;
						  }
						  break;
				case SPECIAL_ENDING1:
						  if (endingIdx_ >= 0) {
							ending1Time = elem->midiTime_;
						  	elem = musElementList_.at(endingIdx_);
							if (startTime <=  elem->midiTime_) theStaff_->timeOffset_ -= elem->midiTime_ - ending1Time;
							endingIdx_ = -1;
						  }
						  break;
				case SEGNO:
						  segnoIdx_ = musElementList_.at();
						  segnoTime_ = elem->midiTime_;
						  break;
				case DAL_SEGNO:   if (segnoIdx_ < 0) break;
						  if (startTime <=  elem->midiTime_) theStaff_->timeOffset_ += elem->midiTime_ - segnoTime_;
						  musElementList_.at(segnoIdx_);
						  segnoIdx_ = -1;
						  break;
				case DAL_SEGNO_AL_CODA:
						  if (segnoIdx_ < 0 || codaStatus_  != -1) break;
						  codaStatus_ = 0;
						  if (startTime <=  elem->midiTime_) theStaff_->timeOffset_ += elem->midiTime_ - segnoTime_;
						  musElementList_.at(segnoIdx_);
						  segnoIdx_ = -2;
						  break;
				case DAL_SEGNO_AL_FINE:
						  if (segnoIdx_ < 0)  break;
						  if (startTime <=  elem->midiTime_) theStaff_->timeOffset_ += elem->midiTime_ - segnoTime_;
						  musElementList_.at(segnoIdx_);
						  segnoIdx_ = -2;
						  break;
				case CODA:	  if (idxOf2ndCodaSign_ < 0 || codaStatus_ < 0) break;
						  if (startTime <=  elem->midiTime_) {
						  	theStaff_->timeOffset_ += elem->midiTime_ - timeOf2ndCoda_;
						  }
						  musElementList_.at(idxOf2ndCodaSign_);
						  idxOf2ndCodaSign_ = -1;
						  break;
			}
		}
		else if (elem->getType() == T_CHORD) {
			chord = (NChord *) elem;
			if ((chord->status_ & STAT_FERMT) == 0) continue;
			newsign = new NSign(&NResource::nullMainProps_, &NResource::nullprops_, TEMPO_SIGNATURE);
			newsign->setTempo(actualTempo/2);
			newsign->setRealMidiTime(chord->midiTime_ + theStaff_->timeOffset_);
			ttrack->insertTempoSign(newsign);
			newsign = new NSign(&NResource::nullMainProps_, &NResource::nullprops_, TEMPO_SIGNATURE);
			newsign->setTempo(actualTempo);
			newsign->setRealMidiTime(chord->midiTime_ + chord->getMidiLength() + theStaff_->timeOffset_);
			ttrack->insertTempoSign(newsign);
		}
	}
}

bool NVoice::voiceHasPedalMarks() {
	NMusElement *elem;
	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		if (elem->getType() == T_CHORD && (elem->status2_ & (STAT2_PEDAL_ON | STAT2_PEDAL_OFF))) return true;
	}
	return false;
}

int NVoice::determineAnacrusis() {
	NMusElement *elem;
	int old_idx;
	int total = 0, countof128th = 128;

	old_idx = musElementList_.at();
	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		switch (elem->getType()) {
			case T_CHORD:
			case T_REST: total += elem->getMidiLength();	
				     if (total > MULTIPLICATOR*countof128th) {
					if (old_idx >= 0) musElementList_.at(old_idx);
					return 0;
				     }
				     break;
			case T_TIMESIG:
				countof128th = ((NTimeSig *) elem)->numOf128th();
				break;
			case T_SIGN:
				if ((elem->getSubType() & BAR_SYMS) == 0) break;
				if (old_idx >= 0) musElementList_.at(old_idx);
				return ((total / MULTIPLICATOR) % countof128th);
		}
	}
	if (old_idx >= 0) musElementList_.at(old_idx);
	return total / MULTIPLICATOR;
}
	

int NVoice::getMidiPos() const {
	if (currentElement_) {
		return currentElement_->getXpos();
	}
	return 0;
}

void NVoice::startPlaying(int starttime) {
	NSign *sign;
	bool programChangeSeen = false;
	int i;

	if (currentElement_) {
		currentElement_->setActual(false);
		currentElement_->draw();
	}
	computeVolumesAndSearchFor2ndCodaSign();
	playPosition_ = musElementList_.first();
	u1_.pending_prog_change = -1;
	while (playPosition_) {
		if (firstVoice_) {
			switch (playPosition_->getType()) {
			case T_SIGN:
				sign = (NSign *) playPosition_;
				switch(playPosition_->getSubType()) {
					case PROGRAM_CHANGE:
						NResource::mapper_->changeProg(theStaff_->getChannel(), sign->getProgram());
							programChangeSeen = true;
							break;
				}
				break;
			case T_CLEF: theStaff_->playClef_ = (NClef *) playPosition_;
				break;
			case T_KEYSIG:  if (theStaff_->playKeySig_) {
						delete theStaff_->playKeySig_;
					}
					theStaff_->playKeySig_ = new NKeySig(main_props_ , &(theStaff_->staff_props_));
					theStaff_->playKeySig_->changeInContextKeySig((NKeySig *) playPosition_); /* for context presentation only */
				break;
			}
		}
		if (playPosition_->midiTime_ >= starttime) {
			break;
		}
		playPosition_ = musElementList_.next();
	}
	repeatIdx_ = 0;
	repeatTime_ = 0;
	endingIdx_ = -1;
	segnoIdx_ = -1;
	codaStatus_ = -1;
	stopped_at_fine_ = false;
	theStaff_->timeOffset_ = 0;
	if (!programChangeSeen) 
		NResource::mapper_->changeProg(theStaff_->getChannel(), theStaff_->getVoice());
	NResource::mapper_->changeReverb(theStaff_->getChannel(), theStaff_->reverb_);
	NResource::mapper_->changeChorus(theStaff_->getChannel(), theStaff_->chorus_);
	NResource::mapper_->changePan(theStaff_->getChannel(), theStaff_->pan_);
	actualMidiEvent_ = &(midievents_[0]);
	for (i = 0; i < MIDI_EVENT_RING; i++) {
		 midievents_[i].valid = false;
		 midievents_[i].midi_prog_change = -1;
		 midievents_[i].partlength = 0;
	}
	dynEndPos_ = vaEndPos_ = trillEndPos_ = vaEndPos_= vaOffset_ = 0;
	inVolumeCrtlMode_ = false;
	theStaff_->pending_clef_ = 0;
}

void NVoice::stopPlaying() {
	NMusElement *elem;
	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		elem->setActual(false);
	}
	if (currentElement_) {
		currentElement_->setActual(true);
	}

}

void NVoice::setMarker() {
	repeatIdx_ = musElementList_.at();
}

void NVoice::setSegnoMarker() {
	segnoIdx_ = musElementList_.at();
}

void NVoice::setCodaMarker(int timeOf2ndCoda) {
	NMusElement *elem;

	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		if (elem->midiTime_ >= timeOf2ndCoda) {
			idxOf2ndCodaSign_ = musElementList_.at();
			return;
		}
	}
}

void NVoice::gotoCodaMarker() {
	if (idxOf2ndCodaSign_ < 0) return;
	playPosition_ = musElementList_.at(idxOf2ndCodaSign_);
	idxOf2ndCodaSign_ = -1;
	actualMidiEvent_->valid = false;
}

void NVoice::gotoMarker(bool again) {
	dynEndPos_ = vaEndPos_ = trillEndPos_ = vaOffset_ = 0;
	if (repeatIdx_ >= 0) {
		playPosition_ = musElementList_.at(repeatIdx_);
		actualMidiEvent_->valid = false;
		if (again) return;
		endingIdx_ = musElementList_.at();
		repeatIdx_ = -1;
	}
	else {
		endingIdx_ = -1;
	}
}

void NVoice::gotoSegnoMarker() {
	if (segnoIdx_ < 0) return;
	dynEndPos_ = vaEndPos_ = trillEndPos_ = vaOffset_ = 0;
	playPosition_ = musElementList_.at(segnoIdx_);
	actualMidiEvent_->valid = false;
}

void NVoice::handleEnding1() {
	if (endingIdx_ >= 0) {
		playPosition_ = musElementList_.at(endingIdx_);
		actualMidiEvent_->valid = false;
		endingIdx_ = -1;
	}
}


NMidiEventStr* NVoice::getNextMidiEvent(int mtime, bool reachInfo) {
	bool found = false;
	bool isGraceNote = false;
	NMidiEventStr *note_halt;
	QList<NNote> *notelist;
	NNote *note;
	bool partOfTie;
	NChord *chord;
	NSign *sign;
	int ending1Time;
	if (muted_ || stopped_at_fine_)  return 0;
	if (actualMidiEvent_->valid) {
		return actualMidiEvent_;
	}
	while (!found && playPosition_) {
		switch (playPosition_->getType ()) {
		case T_CLEF:
			theStaff_->pending_clef_ = (NClef *) playPosition_;
			playPosition_ = musElementList_.next();
			break;
		case T_KEYSIG:
			if (theStaff_->playKeySig_) {
				delete theStaff_->playKeySig_; 
			}
			theStaff_->playKeySig_ = new NKeySig(main_props_ , &(theStaff_->staff_props_));
			theStaff_->playKeySig_->change((NKeySig *) playPosition_); /* for context presentation only */
			theStaff_->playKeySig_->setClef(theStaff_->playClef_);
			playPosition_ = musElementList_.next();
			break;
		case T_CHORD:
			chord = (NChord *) playPosition_;
			if (chord->status_ & STAT_GRACE) {
				if (playPosition_->midiTime_ <= 0) {
					playPosition_ = musElementList_.next();
					continue;
				}
				isGraceNote = true;
				if (chord->getGraceMidiStartTime() + theStaff_->timeOffset_ < mtime) {
/*
					fprintf(stderr, "chord skipped\n");
*/
					playPosition_ = musElementList_.next();
				}
				else {
					found = true;
				}
				break;
			}
			if (playPosition_->midiTime_ + theStaff_->timeOffset_ < mtime) {
/*
				fprintf(stderr, "chord skipped\n");
*/
				playPosition_ = musElementList_.next();
			}
			else {
				found = true;
			}
			break;
		case T_SIGN:
			switch (playPosition_->getSubType()) {
				case REPEAT_OPEN: repeatIdx_ = musElementList_.at(); 
						  repeatTime_ = playPosition_->midiTime_;
						  repeatCount_ = 1;
						  theStaff_->setMarker();
						  break;
				case REPEAT_CLOSE: 
						  if (repeatIdx_ >= 0) {
							dynEndPos_ = vaEndPos_ = trillEndPos_ = vaOffset_ = 0;
						  	theStaff_->timeOffset_ += playPosition_->midiTime_ - repeatTime_;
							if (repeatCount_ == ((NSign *) playPosition_)->getRepeatCount() - 1)  {
								endingIdx_ = musElementList_.at();
							}
						  	if (++repeatCount_ < ((NSign *) playPosition_)->getRepeatCount()) {
								musElementList_.at(repeatIdx_);
								theStaff_->gotoMarker(true);
								break;
							}
							musElementList_.at(repeatIdx_);
							theStaff_->gotoMarker(false);
							repeatIdx_ = -1;
							repeatCount_ = 1;
						  }
						  else {
							endingIdx_ = -1;
						  }
						  break;
				case REPEAT_OPEN_CLOSE:
						  if (repeatIdx_ >= 0) {
							dynEndPos_ = vaEndPos_ = trillEndPos_ = vaOffset_ = 0;
							endingIdx_ = musElementList_.at();
						  	theStaff_->timeOffset_ += playPosition_->midiTime_ - repeatTime_;
							musElementList_.at(repeatIdx_);
							repeatIdx_ = -1;
						  	theStaff_->gotoMarker(false);
						  }
						  else {
							endingIdx_ = -1;
							repeatIdx_ = musElementList_.at(); 
							repeatTime_ = playPosition_->midiTime_;
							theStaff_->setMarker();
						  }
						  break;
				case SPECIAL_ENDING1:
						  if (endingIdx_ >= 0) {
							ending1Time = playPosition_->midiTime_;
						  	playPosition_ = musElementList_.at(endingIdx_);
							theStaff_->timeOffset_ -= playPosition_->midiTime_ - ending1Time;
							endingIdx_ = -1;
						  }
						  theStaff_->handleEnding1();
						  break;
				case SEGNO:
						  segnoIdx_ = musElementList_.at();
						  segnoTime_ = playPosition_->midiTime_;
						  theStaff_->setSegnoMarker();
						  break;
				case DAL_SEGNO:   if (segnoIdx_ < 0) break;
						  dynEndPos_ = vaEndPos_ = trillEndPos_ = vaOffset_ = 0;
						  theStaff_->timeOffset_ += playPosition_->midiTime_ - segnoTime_;
						  musElementList_.at(segnoIdx_);
						  segnoIdx_ = -1;
						  theStaff_->gotoSegnoMarker();
						  break;
				case DAL_SEGNO_AL_CODA:
						  if (segnoIdx_ < 0 || codaStatus_  != -1) break;
						  codaStatus_ = 0;
						  dynEndPos_ = vaEndPos_ = trillEndPos_ = vaOffset_ = 0;
						  theStaff_->timeOffset_ += playPosition_->midiTime_ - segnoTime_;
						  musElementList_.at(segnoIdx_);
						  segnoIdx_ = -2;
						  theStaff_->gotoSegnoMarker();
						  break;
				case DAL_SEGNO_AL_FINE:
						  if (segnoIdx_ < 0)  break;
						  dynEndPos_ = vaEndPos_ = trillEndPos_ = vaOffset_ = 0;
						  theStaff_->timeOffset_ += playPosition_->midiTime_ - segnoTime_;
						  musElementList_.at(segnoIdx_);
						  segnoIdx_ = -2;
						  theStaff_->gotoSegnoMarker();
						  break;
				case CODA:	  if (idxOf2ndCodaSign_ < 0 || codaStatus_ < 0) break;
						  dynEndPos_ = vaEndPos_ = trillEndPos_ = vaOffset_ = 0;
						  theStaff_->timeOffset_ += playPosition_->midiTime_  - timeOf2ndCoda_;
						  musElementList_.at(idxOf2ndCodaSign_);
						  idxOf2ndCodaSign_ = -1;
						  theStaff_->gotoCodaMarker();
						  break;
				case FINE:	  if (segnoIdx_ != -2) break;
						  stopped_at_fine_ = true;
						  theStaff_->stopAllVoices();
						  return 0;
				case PROGRAM_CHANGE:
						u1_.pending_prog_change = ((NSign *) playPosition_)->getProgram();
						break;
			}
			playPosition_ = musElementList_.next();
			break;
		case T_TIMESIG:
			if (reachInfo) {
				actualMidiEvent_->ev_time = (playPosition_->midiTime_ + theStaff_->timeOffset_);
				actualMidiEvent_->midi_cmd = MTIMESIG;
				actualMidiEvent_->midi_channel = 0;
				actualMidiEvent_->volume = 0;
				actualMidiEvent_->valid = false;
				actualMidiEvent_->length = 0;
				actualMidiEvent_->notelist = 0;
				actualMidiEvent_->xpos = 0;
				actualMidiEvent_->from = 0;
				actualMidiEvent_->midi_prog_change = -1;
				actualMidiEvent_->ref = playPosition_;
				actualMidiEvent_->notehalt->valid = false;
				playPosition_ = musElementList_.next();
				return actualMidiEvent_;
			}
			playPosition_ = musElementList_.next();
			break;
		default:
			playPosition_ = musElementList_.next();
			break;
		}
	}
	if (found) {
		chord = (NChord *) playPosition_;
		note_halt = actualMidiEvent_->notehalt;
		if (isGraceNote) {
			actualMidiEvent_->ev_time = (chord->getGraceMidiStartTime() + theStaff_->timeOffset_);
		}
		else {
			actualMidiEvent_->ev_time = (playPosition_->midiTime_ + theStaff_->timeOffset_);
		}
		if (theStaff_->pending_clef_) {
			if (chord->midiTime_ >= theStaff_->pending_clef_->midiTime_) {
				theStaff_->playClef_ = theStaff_->pending_clef_;
				theStaff_->pending_clef_ = 0;
				if (theStaff_->playKeySig_) {
					theStaff_->playKeySig_->setClef(theStaff_->playClef_);
				}
			}
		}
		if (chord->va_) {
			if (chord->va_ < 0) vaOffset_ = -12; else vaOffset_ =  12;
			vaEndPos_ =  chord->getVaEnd();
		}
		if (vaEndPos_ && playPosition_->getBbox()->left() > vaEndPos_) {
			vaEndPos_ = 0;
			vaOffset_ = 0;
		}
		for (note = chord->getNoteList()->first(); note; note = chord->getNoteList()->next()) {
			note->midiPitch = theStaff_->playClef_->line2midiTab_[note->line+LINE_OVERFLOW]+note->offs+theStaff_->playClef_->getShift()+theStaff_->transpose_+vaOffset_;
		}
		actualMidiEvent_->midi_cmd = MNOTE_ON;
		note_halt->midi_cmd = MNOTE_OFF;
		note_halt->midi_channel = actualMidiEvent_->midi_channel = theStaff_->getChannel();
		note_halt->volume =
		actualMidiEvent_->volume = chord->auxInfo_.dynamic_descr.volume;
		note_halt->valid = true;
		actualMidiEvent_->volum_ctrl_change = -1;
		actualMidiEvent_->trilloffs = note_halt->trilloffs = 0;
		actualMidiEvent_->status = 0;
		if (chord->dynamic_ || playPosition_->getBbox()->left() <= dynEndPos_) {
#ifdef WITH_FADE_IN
			if ( playPosition_->getMidiLength(true) >= 2* DYNAMIC_PRECISION) {
				actualMidiEvent_->special = SPEC_DYNAMIC;
				dynamicRefTime_ = actualMidiEvent_->internalMidiTime = playPosition_->midiTime_;
				dynamicRefVolume_ = actualMidiEvent_->volume;
				actualMidiEvent_->volume = 127;
				inVolumeCrtlMode_ = true;
				actualMidiEvent_->volum_ctrl_change = dynamicRefVolume_;
				actualMidiEvent_->length = DYNAMIC_PRECISION;
				actualMidiEvent_->partlength = playPosition_->getMidiLength(true) / DYNAMIC_PRECISION  - 1;
				if (chord->dynamic_) {
					dynEndPos_ = chord->getDynamicEnd();
					volIncrease_= chord->auxInfo_.dynamic_descr.increase;
				}
				note_halt->valid = false;
			}
			else {
#endif
				actualMidiEvent_->partlength = 0;
				actualMidiEvent_->special = NO_SPECIAL;
				actualMidiEvent_->length = playPosition_->getMidiLength(true);
				actualMidiEvent_->volume = chord->auxInfo_.dynamic_descr.increase;
				if (chord->dynamic_) {
					dynEndPos_ = chord->getDynamicEnd();
				}
				note_halt->valid = true;
#ifdef WITH_FADE_IN
			}
#endif
		}
		else if ((chord->trill_  || playPosition_->getBbox()->left() <= trillEndPos_) && playPosition_->getMidiLength(true) > TRILL_MIDI_LENGTH) {
			note_halt->special = actualMidiEvent_->special = SPEC_TRILL_DOWN;
			actualMidiEvent_->partlength = playPosition_->getMidiLength(true) / TRILL_MIDI_LENGTH - 1;
			actualMidiEvent_->trillDist =
				 theStaff_->actualKeysig_.determineDistanceUp(
				chord->getNoteList()->first());
			note_halt->trilloffs =
			actualMidiEvent_->trilloffs = actualMidiEvent_->trillDist;

			actualMidiEvent_->length = TRILL_MIDI_LENGTH;
			if (chord->trill_) trillEndPos_ = chord->getTrillEnd();
		}
		else if ((chord->status_ & STAT_ARPEGG) && chord->getNoteList()->count() > 1 && playPosition_->getMidiLength(true) > chord->getNoteList()->count() * ARPEGGIO_MIDI_LENGTH) {
			note_halt->special = actualMidiEvent_->special = SPEC_ARPEGGIO;
			note_halt->arpegg_total = actualMidiEvent_->arpegg_total = chord->getNoteList()->count();
			actualMidiEvent_->partlength = actualMidiEvent_->arpegg_total;
			actualMidiEvent_->length = ARPEGGIO_MIDI_LENGTH;
			actualMidiEvent_->arpegg_current = 0;
			note_halt->valid = false;
		}
		else {
			actualMidiEvent_->length = (playPosition_->status_ & STAT_STACC) ? 
			(playPosition_->getMidiLength(true) >> 1) : playPosition_->getMidiLength(true);
			actualMidiEvent_->partlength = 0;
			note_halt->special = actualMidiEvent_->special = NO_SPECIAL;
		}
		if (inVolumeCrtlMode_ && actualMidiEvent_->volum_ctrl_change == -1) {
			notelist = playPosition_->getNoteList();
			for (partOfTie = false, note = notelist->first(); note && !partOfTie; note = notelist->next()) {
				if (note->status & STAT_PART_OF_TIE) partOfTie = true;
			}
			if (!partOfTie) {
				inVolumeCrtlMode_ = false;
				if (actualMidiEvent_->volum_ctrl_change != -1) {
					note_halt->volume = 
					actualMidiEvent_->volume = actualMidiEvent_->volum_ctrl_change;
				}
				actualMidiEvent_->volum_ctrl_change = 127;
			}
			else {
				actualMidiEvent_->volume = 127;
			}
		}
		if (chord->status2_ & STAT2_PEDAL_ON) actualMidiEvent_->status |= MIDI_STAT_PEDAL_ON;
		if (chord->status2_ & STAT2_PEDAL_OFF) actualMidiEvent_->status  |= MIDI_STAT_PEDAL_OFF;
		note_halt->notelist = 
		actualMidiEvent_->notelist = playPosition_->getNoteList();
		note_halt->xpos = 
		actualMidiEvent_->xpos = playPosition_->getXpos();
		note_halt->from = 
		actualMidiEvent_->from = this;
		note_halt->midi_prog_change = -1;
		if ((actualMidiEvent_->midi_prog_change = u1_.pending_prog_change) >= 0) {
			u1_.pending_prog_change = -1;
		}
		note_halt->ref = 
		actualMidiEvent_->ref = playPosition_;
		actualMidiEvent_->valid = true;
		return actualMidiEvent_;
	}
	return 0;
}

void NVoice::skipAndInvalidate(bool doSkip) {
	if (doSkip) {
		playPosition_ = musElementList_.next();
	}
	actualMidiEvent_->valid = false;
}

void NVoice::skipTeXChord() {
	playPosition_ = musElementList_.next();
	pPtr_ = 0;
}

int NVoice::findNextVolumeSignature() {
	int pos = musElementList_.at();
	NMusElement *elem;

	for (elem = musElementList_.next(); elem; elem = musElementList_.next()) {
		if (elem->getType() != T_SIGN || elem->getSubType() != VOLUME_SIG) continue;
		if (pos >= 0) musElementList_.at(pos);
		return ((NSign *) elem)->getVolume();
	}
	if (pos >= 0) musElementList_.at(pos);
	return -1;
}


void NVoice::computeVolumesAndSearchFor2ndCodaSign() {
	int volume, endvolume;
	int dynamicEndPos;
	int lastVolume;
	int volumeIncreaseStartTime;
	double currentVolumeIncrease;
	NMusElement *elem;
	NChord *chord;
	NRest *rest;
	int endtime;

	dynamicEndPos = 0; lastVolume = -1;
	idxOf2ndCodaSign_ = -1;
	volume = theStaff_->getVolume();
	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		switch (elem->getType()) {
		case T_CHORD: chord = (NChord *) elem; 
			      if (chord->dynamic_) {	
					chord->auxInfo_.dynamic_descr.volume = volume;
					endvolume = findNextVolumeSignature();
                              		endtime = findEndOfCrescendo(chord);
					volumeIncreaseStartTime = chord->midiTime_;
                              		if (endvolume < 0) {
						chord->auxInfo_.dynamic_descr.increase =
						currentVolumeIncrease = 0.0;
					}
					else {
						chord->auxInfo_.dynamic_descr.increase = 
						currentVolumeIncrease = ((double) (endvolume - volume)) / ((double) (endtime - volumeIncreaseStartTime));
						dynamicEndPos = chord->getDynamicEnd();
					}
			      }
			      else if (chord->getBbox()->left() <= dynamicEndPos) {
					lastVolume = chord->auxInfo_.dynamic_descr.volume = volume +
					 		(int) (currentVolumeIncrease * (chord->midiTime_ - volumeIncreaseStartTime));
			      }
			      else if (lastVolume >= 0) {
					chord->auxInfo_.dynamic_descr.volume = lastVolume;
			      }
			      else {
					chord->auxInfo_.dynamic_descr.volume = volume;
			      }
			      break;
		case T_SIGN: switch (elem->getSubType()) {
				case VOLUME_SIG:
			     		volume = ((NSign *) elem) ->getVolume();
			     		lastVolume = -1;
			     		break;
				case CODA: if (!firstVoice_) break;
					switch (idxOf2ndCodaSign_) {
						case -2: idxOf2ndCodaSign_ = musElementList_.at();
							 timeOf2ndCoda_ = elem->midiTime_;
							 theStaff_->setCodaMarker(timeOf2ndCoda_);
							 break;
						case -1: idxOf2ndCodaSign_ = -2;
							 break;
					}
					break;
			      }
			      break;
		}
	}
}


void NVoice::skipChord() {
	NMidiEventStr *next, *note_halt;
	if (actualMidiEvent_->partlength) {
		next = actualMidiEvent_->next;
		note_halt = next->notehalt;
		next->status = actualMidiEvent_->status;
		next->special = actualMidiEvent_->special;
		note_halt->midi_channel = next->midi_channel = actualMidiEvent_->midi_channel;
		note_halt->notelist = next->notelist = actualMidiEvent_->notelist;
		note_halt->xpos = next->xpos = actualMidiEvent_->xpos;
		note_halt->from = next->from = actualMidiEvent_->from;
		note_halt->ref = next->ref = actualMidiEvent_->ref;
		next->partlength = actualMidiEvent_->partlength - 1;
		next->valid = true;
		switch (actualMidiEvent_->special) {
		   case SPEC_TRILL_UP:
			next->midi_cmd = MNOTE_ON;
			note_halt->midi_cmd = MNOTE_OFF;
			next->trillDist = actualMidiEvent_->trillDist;
			next->length = TRILL_MIDI_LENGTH;
			note_halt->volume = next->volume = actualMidiEvent_->volume;
			note_halt->special = next->special = SPEC_TRILL_DOWN;
			note_halt->trilloffs = next->trilloffs = actualMidiEvent_->trillDist;
			next->ev_time = actualMidiEvent_->ev_time + TRILL_MIDI_LENGTH;
			note_halt->valid = true;
			break;
		   case SPEC_TRILL_DOWN: 
			next->midi_cmd = MNOTE_ON;
			note_halt->midi_cmd = MNOTE_OFF;
			next->trillDist = actualMidiEvent_->trillDist;
			next->length = TRILL_MIDI_LENGTH;
			note_halt->special = next->special = SPEC_TRILL_UP;
			next->ev_time = actualMidiEvent_->ev_time + TRILL_MIDI_LENGTH;
			note_halt->valid = true;
			break;
		   case SPEC_ARPEGGIO:
		   	next->midi_cmd = MNOTE_ON;
			note_halt->midi_cmd = MNOTE_OFF;
			next->trilloffs =  note_halt->trilloffs = 0;
			if (actualMidiEvent_->arpegg_current == actualMidiEvent_->arpegg_total - 1) { 
				next->length = actualMidiEvent_->ref->getMidiLength(true) - actualMidiEvent_->arpegg_total * ARPEGGIO_MIDI_LENGTH;
				next->ev_time = actualMidiEvent_->ev_time-10;  /* avoid to note on again */
				note_halt->ev_time = actualMidiEvent_->ev_time + next->length;
				next->arpegg_current = actualMidiEvent_->arpegg_current + 1;
				next->arpegg_total = actualMidiEvent_->arpegg_total;
				next->volum_ctrl_change = -1;
				next->midi_prog_change = -1;
				note_halt->volume = next->volume = actualMidiEvent_->volume;
				note_halt->special = next->special = SPEC_ARPEGGIO;
				next->valid = true;
				note_halt->valid = true;
			}
			else {
				next->length = ARPEGGIO_MIDI_LENGTH;
				next->ev_time = actualMidiEvent_->ev_time + ARPEGGIO_MIDI_LENGTH;
				next->arpegg_current = actualMidiEvent_->arpegg_current + 1;
				next->arpegg_total = actualMidiEvent_->arpegg_total;
				next->volum_ctrl_change = -1;
				next->midi_prog_change = -1;
				note_halt->volume = next->volume = actualMidiEvent_->volume;
				note_halt->special = next->special = SPEC_ARPEGGIO;
				note_halt->valid = false;
			}
			break;
#ifdef WITH_FADE_IN
		   case SPEC_DYNAMIC:
			next->trilloffs =  note_halt->trilloffs = 0;
			next->midi_cmd = MVOL_CONTROL;
			note_halt->midi_cmd = MNOTE_OFF;
			next->length = DYNAMIC_PRECISION;
			note_halt->volume = next->volume = actualMidiEvent_->volume;
			note_halt->special = next->special = SPEC_DYNAMIC;
			next->ev_time = actualMidiEvent_->ev_time + DYNAMIC_PRECISION;
			next->internalMidiTime = actualMidiEvent_->internalMidiTime + DYNAMIC_PRECISION;
			note_halt->volume = next->volume = dynamicRefVolume_+
				(int) (volIncrease_ * (next->internalMidiTime - dynamicRefTime_));
			note_halt->valid = (next->partlength == 0);
			break;
#endif
		}
		actualMidiEvent_ = actualMidiEvent_->next;
	}
	else {
		playPosition_ = musElementList_.next();
		actualMidiEvent_ = actualMidiEvent_->next;
		actualMidiEvent_->valid = false;
	}
}

/*------------------------- repositioning voice --------------------------------*/

NPositStr* NVoice::getElementAfter(int mtime) {
	bool found = false;
	int oldidx;

	if (!playPosition_) return 0;
	if (pPtr_) return pPtr_;
	while (!found && playPosition_) {
		if (playPosition_->midiTime_ < mtime) {
			KMessageBox::error
				(0,
				 i18n("posit: chord skipped"),
				 kapp->makeStdCaption(i18n("Repositioning voice"))
				);
			playPosition_ = musElementList_.next();
		}
		else {
			if (playPosition_->getType() == T_KEYSIG) {
				((NKeySig *) playPosition_)->setPreviousKeySig(lastKeySig_);
				lastKeySig_ =  ((NKeySig *) playPosition_);
				theStaff_->actualKeysig_.change((NKeySig*) playPosition_);
				theStaff_->actualKeysig_.resetAtBar();
				if (theStaff_->actualKeysig_.isDrawable()) {
					found = true;
				}
				else {
					musElementList_.remove();
					playPosition_ = musElementList_.current();
				}
			}
			else {
				found = true;
			}
		}
	}
	if (found) {
		pPtr_ = new NPositStr;
		switch (pPtr_->ev_type = playPosition_->getType()) {
			case T_CHORD:
					if (((NChord *) playPosition_)->status_ & STAT_GRACE) {
						pPtr_->ev_type = STAT_GRACE; /* make "ev_type & PLAYABLE == false" */
					}
			case T_REST:
					pPtr_->ev_time = playPosition_->midiTime_;
					break;
			default:
					if (playPosition_->getType() == T_CLEF) {
						theStaff_->actualClef_.change((NClef*) playPosition_);
					}
					else if (playPosition_->getType() == T_SIGN && 
						(playPosition_->getSubType() & BAR_SYMS)) {
						((NSign *) playPosition_)->setBarNr(barNr_++);
						theStaff_->actualKeysig_.resetAtBar();
					}
					oldidx = musElementList_.at();
					playPosition_ = musElementList_.next();
					if (playPosition_) {
						pPtr_->ev_time = playPosition_->midiTime_;
					}
					else {
						pPtr_->ev_time = midiEndTime_;
					}
					playPosition_ = musElementList_.at(oldidx);
					break;
		}
		QRect *q;
		q = playPosition_->getBbox();
		pPtr_->from = this;
		pPtr_->elem = playPosition_;
		return pPtr_;
	}
	return 0;
}

void NVoice::startRepositioning() {
	theStaff_->actualClef_.change(NResource::nullClef_);
	pPtr_ = 0;
	barNr_ = 2;
	theStaff_->actualKeysig_.change(NResource::nullKeySig_);
	theStaff_->actualKeysig_.setClef(NResource::nullClef_);
	playPosition_ = musElementList_.first();
	lastKeySig_ = 0;
}

int NVoice::findPos(int BarNr) {
	bool found = false;
	NMusElement *elem;
	int res = 0;
	
	for (elem = musElementList_.first(); !found && elem; elem = musElementList_.next()) {
		if (elem->getType() == T_SIGN && elem->getSubType() == SIMPLE_BAR) {
			if (((NSign *) elem)->getBarNr() >= BarNr) {
				found = true;
				res = elem->getXpos();
			}
		}
	}
	return res;
}

void NVoice::computeMidiTime(bool insertBars) {
#define MAXGRACENOTES 5
	int mtime = 0;
	int timeOfLastBar = 0;
	int indexOfLastBar = 0;
	int i, idx, idx0, len1, len2, countBefore, maxticks;
	int num_grace_notes = 0;
	int last_note_time = -1;
	bool chord_seen;
	bool not_grace_seen;
	QList <NMusElement> elems;
	NMusElement *elem;
	theStaff_->staff_props_.measureLength = WHOLE_LENGTH;
	NChord *graceNotes[MAXGRACENOTES];

	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		elem->midiTime_ = mtime;
		not_grace_seen = true;
		chord_seen = false;
		switch(elem->getType()) {
			case T_CHORD: if (((NChord *) elem)->status_ & STAT_GRACE) {
				 	if (num_grace_notes < MAXGRACENOTES) {
						graceNotes[num_grace_notes++] = (NChord *) elem;
					}
					not_grace_seen = false;
				      }
				      else {
					for (i = 0; i < num_grace_notes; i++) {
						graceNotes[i]->setGraceMidiStartTime(mtime - (num_grace_notes - i) * INTERNAL_GRACE_MIDI_LENGTH);
						graceNotes[i]->midiTime_ = mtime;
					}
					num_grace_notes = 0;
				      }
				      chord_seen = true;
				      break;	
			case T_TIMESIG: theStaff_->staff_props_.measureLength = MULTIPLICATOR * ((NTimeSig *) elem)->numOf128th();
					break;
			case T_SIGN: if (!insertBars || !firstVoice_ ) break;
				     if ((elem->getSubType() & BAR_SYMS) == 0) break;
				     timeOfLastBar = elem->midiTime_; 
				     indexOfLastBar = musElementList_.at();
				     break;
				     
		}
		mtime += elem->getMidiLength();
		if (chord_seen && !not_grace_seen) {
			last_note_time = mtime;
		}
		else if (not_grace_seen) {
			if (last_note_time >= 0 && num_grace_notes) {
				for (i = 0; i < num_grace_notes; i++) {
					graceNotes[i]->setGraceMidiStartTime(last_note_time +  i * INTERNAL_GRACE_MIDI_LENGTH);
				}
			}
			last_note_time =  -1;
			num_grace_notes = 0;
		}
	}
	midiEndTime_ = mtime;
	if (!insertBars || !firstVoice_) return;
	if (midiEndTime_ - timeOfLastBar <= (maxticks = theStaff_->staff_props_.measureLength)) return;
	elem = musElementList_.at(indexOfLastBar);
	while (elem && elem->midiTime_ + elem->getMidiLength() <= timeOfLastBar + maxticks) {
		elem = musElementList_.next();
	}
	if (!elem) return;
	idx = musElementList_.at();
	switch (elem->getType()) {
		case T_CHORD: 
		case T_REST: 
			     len2 = elem->midiTime_ + elem->getMidiLength() - (timeOfLastBar + maxticks);
			     len1 = elem->getMidiLength() - len2;
			     elems.append(elem);
			     countBefore = musElementList_.count();
			     collectAndInsertPlayable(&elems, len1, false);
			     idx0 = idx;
			     idx = musElementList_.at();
			     musElementList_.insert(idx, new NSign(main_props_, &(theStaff_->staff_props_), SIMPLE_BAR));
			     elems.append(elem);
			     collectAndInsertPlayable(&elems, len2, true);
			     break;
	}
	createUndoElement(idx0, 0, musElementList_.count() - countBefore);
	elem = musElementList_.at(indexOfLastBar);
	mtime = timeOfLastBar;
	for (; elem; elem = musElementList_.next()) {
		elem->midiTime_ = mtime;
		mtime += elem->getMidiLength();
	}
	midiEndTime_ = mtime;
}

int NVoice::placeAt(int xpos, int sequNr) {
	int width;
	if (playPosition_->getType() == T_CHORD) {
		((NChord *) playPosition_)->checkAcc();
	}
	playPosition_->reposit(xpos, sequNr);
	if (playPosition_->lastBeamed()) {
		((NChord *) playPosition_)->computeBeames(stemPolicy_);
	}
	if (playPosition_->status_ & STAT_LAST_TUPLET) {
		playPosition_->computeTuplet();
	}
	width =  playPosition_->getBbox()->width();
	playPosition_ = musElementList_.next();
	pPtr_ = 0;
	return width;
}

/* --------------------------- export musixtex -------------------------------------*/

bool NVoice::testSpecialEnding(int *num) {
	*num = 1;
	if (!playPosition_) return false;
	switch (playPosition_->getType()) {
		case T_SIGN: switch (playPosition_->getSubType()) {
				case SPECIAL_ENDING1: *num = 1; return true;
				case SPECIAL_ENDING2: *num = 2; return true;
			     }
			     break;
	}
	return false;
}


/* -----------------------------references between voices -------------------------*/

void NVoice::resetSpecialElement() {
	specialElement_ = musElementList_.first();
}


void NVoice::syncSpecialElement(int xpos) {
	if (!specialElement_) return;
	if (specialElement_->getXpos() > xpos) return;
	for (;specialElement_ && specialElement_->getXpos() <= xpos; specialElement_ = musElementList_.next());
}

void NVoice::mark() {
	savePosition_ = musElementList_.at();
}

void NVoice::gotoMarkedPosition() {
	if (savePosition_ >= 0) musElementList_.at(savePosition_);
}

NMusElement *NVoice::countBarSymsBetween(int firstXpos, int actualXpos, int *count_of_bar_syms) {
	int oldidx;
	NMusElement *elem, *lastBarSym = 0;
	*count_of_bar_syms = 0;


	oldidx = musElementList_.at();
	for (elem = musElementList_.first(); elem && elem->getXpos() < firstXpos; elem = musElementList_.next()) {
		if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
			lastBarSym = elem;
		}
	}
	if (!elem) {
		if (oldidx >= 0) {
			musElementList_.at(oldidx);
		}
		else {
			musElementList_.last(); musElementList_.next();
		}
		return lastBarSym;
	}
	for (;elem && elem->getXpos() <= actualXpos; elem = musElementList_.next()) {
		if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
			//if (oldidx >= 0) musElementList_.at(oldidx);
			lastBarSym = elem;
			(*count_of_bar_syms)++;
		}
	}
	if (oldidx >= 0) {
		musElementList_.at(oldidx);
	}
	else {
		musElementList_.last(); musElementList_.next();
	}
	return lastBarSym;
}

NMusElement *NVoice::checkSpecialElement(int xpos, int *volta) {
	NMusElement *elem;
	if (volta) *volta = 0;
	if (!specialElement_) return 0;
	if (specialElement_->getXpos() > xpos) return 0;
	while (specialElement_ && specialElement_->getXpos() <= xpos) {
		switch (specialElement_->getType()) {
			case T_SIGN: if ((specialElement_->getSubType() & BAR_SYMS)) {
				       elem = specialElement_;
				       if (volta) {
					  specialElement_ = musElementList_.next();
					  if (specialElement_ && specialElement_->getType() == T_SIGN) {
						switch (specialElement_->getSubType()) {
							case SPECIAL_ENDING1: *volta = 1; break;
							case SPECIAL_ENDING2: *volta = 2; break;
							default: return elem;
						}
					  }
				       }
				       specialElement_ = musElementList_.next();
				       return elem;
				     }
				     break;
			case T_KEYSIG:
			case T_CLEF: elem = specialElement_;
				     specialElement_ = musElementList_.next();
				     return elem;
		}
		specialElement_ = musElementList_.next();
	}
	return 0;
}
				
				     
				   
	

/*-------------------------- writing the voice  ------------------------------------*/

void NVoice::prepareForWriting() {
	theStaff_->actualKeysig_.reset();
	theStaff_->actualClef_.change(NResource::nullClef_);
	musElementList_.first();
}


NClef* NVoice::getFirstClef() {
	NMusElement *elem;

	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		if (elem->getType() == T_CLEF) {
			return (NClef *) elem;
		}
	}
	return NResource::nullClef_;
}

int NVoice::determineMultiRest() {
	NMusElement *elem;
	bool go_on = true;
	int oldidx;
	int multirestlen = 0;

	oldidx = musElementList_.at();
	for (elem = musElementList_.current(); elem && go_on; elem = musElementList_.next()) {
		switch(elem->getType()) {
			case T_SIGN:
				switch (elem->getSubType ()) {
					case REPEAT_OPEN:
					case REPEAT_CLOSE:
					case TEMPO_SIGNATURE: break;
					default: go_on = false;
				}
				break;
			case T_REST:
				switch (elem->getSubType ()) {
					case MULTIREST: multirestlen = ((NRest *) elem)->getMultiRestLength();
							go_on = false;
							break;
					default: go_on = false;
				}
				break;
			default: go_on = false;
		}
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
	return multirestlen;
}

NTimeSig* NVoice::getFirstTimeSig() {
	NMusElement *elem;

	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		switch(elem->getType()) {
			case T_TIMESIG:
				return (NTimeSig *) elem;
			case T_SIGN:
				if (elem->getSubType() == SIMPLE_BAR) {
					return 0;
				}
				break;
		}
	}
	return 0;
}


NKeySig *NVoice::getFirstKeysig() {
	int i = 0;
	NMusElement *elem;

	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		i++;
		switch(elem->getType()) {
			case T_KEYSIG:
				return (NKeySig *) elem;
			case T_SIGN:
				if (elem->getSubType() == SIMPLE_BAR) {
					return NResource::nullKeySig_;
				}
				break;
		}
	}
	return NResource::nullKeySig_;
}

NMusElement *NVoice::getCurrentPosition() {
	return musElementList_.current();
}

NMusElement *NVoice::getNextPosition() {
	return musElementList_.next();
}

NMusElement *NVoice::getPrevPosition() {
	return musElementList_.prev();
}

NMusElement *NVoice::getFirstPosition() {
	return musElementList_.first();
}

NMusElement *NVoice::getLastPosition() {
	return musElementList_.last();
}

bool NVoice::removeLastPosition() {
	return musElementList_.removeLast();
}

QString NVoice::determineGraceKind(int *status) {
	QString graceString;
	int oldidx;
	NMusElement *elem;
	bool grace_after;
	bool stroken = false;
	bool slured = false;
	bool sixteenth = false;
	int grace_count = 0;

	
	*status = GRACE_PMX_OK;
	elem = musElementList_.current();
	if (elem == 0 || elem->getType() != T_CHORD || !(elem->status_ & STAT_GRACE)) {
		NResource::abort("NVoice::determineGraceKind: internal error");
	}
	oldidx = musElementList_.at();
	elem = musElementList_.prev();
	grace_after = (elem && elem->getType() == T_CHORD && !(elem->status_ & STAT_GRACE));
	elem = musElementList_.at(oldidx);
	while (elem->getType() == T_CHORD && (elem->status_ & STAT_GRACE)) {
		grace_count++;
		if (elem->getSubType() == INTERNAL_MARKER_OF_STROKEN_GRACE) {
			stroken = true;
		}
		else if (stroken || sixteenth) {
			*status = WARN_MIXED_GRACES;
		}
	        else if (elem->getSubType() == NOTE16_LENGTH) {
			if (stroken) {
				*status = WARN_MIXED_GRACES;
			}
			sixteenth = true;
		}
		if (elem->status_ & STAT_SLURED) slured = true;
		elem = musElementList_.next();
	}
	musElementList_.at(oldidx);
	if (elem->getType() == T_CHORD) grace_after = false;
	else if (!grace_after) *status = GRACE_PMX_ERROR;
	if (grace_count > 1) graceString.sprintf("G%d", grace_count); 
	else graceString = "G";
	if (grace_after) graceString += "A";
	if (sixteenth) graceString += "m2";
	if (stroken) graceString += "x";
	if (slured) graceString += "s";
	return graceString;
}
	
		
	
	

/*-------------------- dealing with ties -----------------------------------------*/

void NVoice::handleChordTies(NChord *chord, bool find_member) {
	NNote *note;
	QList<NNote> *noteList;

	noteList = chord->getNoteList();
	for (note = noteList->first(); note; note = noteList->next()) {
		reconnectTies(note);
		if (find_member && (note->status & STAT_TIED)) {
			findTieMember(note);
		}
	}
}

void NVoice::findTieMember(NNote *part) {
	int oldidx;
	int oldpartidx;
	bool found = false;
	NMusElement *mus_elem;
	NNote *note, *new_part;
	QList<NNote> *noteList;

	oldidx = musElementList_.at();
	if (musElementList_.find(part->chordref) == -1) {
		NResource::abort("findTieMember: internal error", 1);
	}
	mus_elem = musElementList_.next();
	while (!found && mus_elem) {
		if (mus_elem->getType() == T_CHORD) {
			noteList = mus_elem->getNoteList();
			oldpartidx = noteList->at();
			for (note = noteList->first(); !found && note; note = noteList->next()) {
				if (note->line == part->line && note->offs == part->offs) {
					found = true;
					part->tie_forward = note;
					note->tie_backward = part;
					note->status |= STAT_PART_OF_TIE;
				}
			}
			if (oldpartidx >= 0)  noteList->at(oldpartidx);
		}
		mus_elem = musElementList_.next();
	}
	if (!found) {
		new_part = new NNote;
		new_part->line = part->line;
		new_part->offs  = part->offs;
		new_part->tie_forward = 0;
		new_part->tie_backward = part;
		new_part->status = STAT_VIRTUAL;
		new_part->status &= (~STAT_TIED);
		new_part->status |= STAT_PART_OF_TIE;
		new_part->tie_start_point_up = QPoint((int) ((float) (theStaff_->getWidth() +main_props_->tp->getLeftX()) / main_props_->zoom+5),
				 part->nbase_draw_point.y()+NResource::nbasePixmapHeight_);
		new_part->tie_start_point_down = QPoint((int) ((float) (theStaff_->getWidth() +main_props_->tp->getLeftX()) / main_props_->zoom+5),
				 part->nbase_draw_point.y());
		new_part->tie_back_point_up = QPoint((int) ((float) (theStaff_->getWidth() +main_props_->tp->getLeftX()) / main_props_->zoom+2),
				 part->nbase_draw_point.y()+NResource::nbasePixmapHeight_+4);
		new_part->tie_back_point_down = QPoint((int) ((float) (theStaff_->getWidth() +main_props_->tp->getLeftX()) / main_props_->zoom+2),
				 part->nbase_draw_point.y()+NResource::nbasePixmapHeight_-4);
		new_part->chordref = 0;
		part->tie_forward = new_part;
		virtualChord_.append(new_part);
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
}

void NVoice::reconnectTies(NNote *part) {
	int oldidx;
	NNote *note, *successor;
	NMusElement *mus_elem;
	QList<NNote> *noteList;

	oldidx = musElementList_.at();
	if (musElementList_.find(part->chordref) == -1) {
		NResource::abort("reconnectTies: internal error");
	}
	for (mus_elem = musElementList_.prev(); mus_elem; mus_elem = musElementList_.prev()) {
		if (mus_elem->getType() != T_CHORD) continue;
		noteList = mus_elem->getNoteList();
		for (note = noteList->first(); note; note = noteList->next()) {
			if (note->line == part->line && note->offs == part->offs) {
				if (note->status & STAT_TIED) {
					successor = note->tie_forward;
					note->tie_forward = part;
					part->tie_backward = note;
					part->status |= STAT_PART_OF_TIE;
					if (successor->status & STAT_VIRTUAL) {
						if (virtualChord_.find(successor) == -1) {
							NResource::abort("reconnectTies: problem with virtual chord");
						}
						virtualChord_.remove();
					}
					else if (successor != part) {
						successor->tie_backward = 0;
						successor->status &= (~STAT_PART_OF_TIE);
					}
				}
				else {
					part->tie_backward = 0;
					part->status &= (~STAT_PART_OF_TIE);
				}
				if (oldidx >= 0) musElementList_.at(oldidx);
				return;
			}
		}
	}
	part->tie_backward = 0;
	part->status &= (~STAT_PART_OF_TIE);
	if (oldidx >= 0) musElementList_.at(oldidx);
}

void NVoice::reconnectFileReadTies(NNote *part) {
	int oldidx;
	NNote *note;

	oldidx = musElementList_.at();
	for (note = virtualChord_.first(); note; note = virtualChord_.next()) {
		if (note->status & STAT_PART_OF_TIE) {
			if (note->line == part->line) {
				part->tie_backward = note->tie_backward;
				part->tie_backward->tie_forward = part;
				part->offs = note->offs;
				part->status |= STAT_PART_OF_TIE;
				virtualChord_.remove();
				if (oldidx >= 0) musElementList_.at(oldidx);
				return;
			}
		}
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
}

void NVoice::reconnectDeletedTies(NNote *part) {
	NNote *before;
	if (part->status & STAT_TIED) {
		if (part->tie_forward->status & STAT_VIRTUAL) {
			if (virtualChord_.find(part->tie_forward) != -1) {
				virtualChord_.remove();
			}
			else {
				NResource::abort("reconnectDeletedTies: error with virtual chord");
			}
		}
		else {
			part->tie_forward->tie_backward = 0;
			part->tie_forward->status &= (~STAT_PART_OF_TIE);
		}
	}
	if (part->status & STAT_PART_OF_TIE) {
		before = part->tie_backward;
		findTieMember(before);
	}
}

void NVoice::breakTies(NChord *chord) {
	NNote *note;
	for (note = chord->getNoteList()->first(); note; note = chord->getNoteList()->next()) {
		if (note->status & STAT_TIED) {
			if (note->tie_forward->status & STAT_VIRTUAL) {
				if (virtualChord_.find(note->tie_forward) != -1) {
					virtualChord_.remove();
				}
				else {
					NResource::abort("breakTies: error with virtual chord");
				}
			}
			else {
				note->tie_forward->status &= (~STAT_PART_OF_TIE);
				note->tie_forward->tie_backward = 0;
			}
		}
		note->tie_forward = 0;
	}
}


void NVoice::reconnectTiesAtferMove(NChord *chord) {
	NNote *note;
	for (note = chord->getNoteList()->first(); note; note = chord->getNoteList()->next()) {
		if (note->status & STAT_PART_OF_TIE) {
			findTieMember(note->tie_backward);
		}
		note->status &= (~STAT_PART_OF_TIE);
		note->tie_backward = 0;
		reconnectTies(note);
		if (note->status & STAT_TIED) {
			findTieMember(note);
		}
	}
}

void NVoice::reconnectCopiedTies(NChord *chord) {
	chord->calculateDimensionsAndPixmaps();
	handleChordTies(chord, true);
	chord->calculateDimensionsAndPixmaps();
}


/*--------------------------- appending due to reading ---------------------------*/


void NVoice::appendNoteAt(int line, int offs, unsigned int status) {
	NNote *note;
	note = musElementList_.current()->insertNewNote(line, offs, STEM_POL_INDIVIDUAL, status);
	if (note) {
		reconnectTies(note);
		if (status & STAT_TIED) {
			findTieMember(note);
		}
	}
}

bool NVoice::buildTuplet(NMusElement *elem0, NMusElement *elem1, char numNotes, char playtime) {
	bool found = false;
	QList<NMusElement> *tupletlist;

	if (musElementList_.find(elem1) == -1) return false;
	if (musElementList_.find(elem0) == -1) return false;

	tupletlist = new QList<NMusElement>();
	for (;elem0  && !found; elem0 = musElementList_.next()) {
		found = elem0 == elem1;
		if (!(elem0->getType() & PLAYABLE)) return false;
		tupletlist->append(elem0);
	}
	NMusElement::computeTuplet(tupletlist, numNotes, playtime);
	return true;
}

bool NVoice::buildTuplet2(NMusElement *elem0, NMusElement *elem1, char numNotes, int playlength, bool dot) {
	bool found = false;
	int tupletsum = 0;
	int length;
	QList<NMusElement> *tupletlist;

	if (musElementList_.find(elem1) == -1) return false;
	if (musElementList_.find(elem0) == -1) return false;

	tupletlist = new QList<NMusElement>();
	for (;elem0  && !found; elem0 = musElementList_.next()) {
		found = elem0 == elem1;
		if (!(elem0->getType() & PLAYABLE)) return false;
		tupletsum += elem0->getSubType();
		tupletlist->append(elem0);
	}
	length = (128 / playlength * MULTIPLICATOR) / (tupletsum / numNotes);
	if (dot) {length = length * 3; length /= 2;}
	NMusElement::computeTuplet(tupletlist, numNotes, length);
	return true;
}

void NVoice::insertAtTime(unsigned int time, NMusElement *elem, bool splitPlayables) {
	NMusElement *el, *lastPlayable;
	NRest *newRest;
	NChord *newChord;
	QList<NNote> *noteList;
	NNote *note;
	int dotcount;
	int idx, lastPlayableIdx = -1;
	int len, len1, len2, restlen;

	computeMidiTime(false);
	if (time > midiEndTime_) {
		musElementList_.append(elem);
		computeMidiTime(false);
		return;
	}

	for (el = musElementList_.first(); el; el = musElementList_.next()) {
		if (el->midiTime_ >= (int) time && (el->getType() & PLAYABLE)) {
			if (splitPlayables && el->midiTime_ > (int) time && lastPlayableIdx >=0 &&
			    lastPlayable->midiTime_ + lastPlayable->getMidiLength() > time) {
				len1 = time - lastPlayable->midiTime_;
				len2 = lastPlayable->getMidiLength() - len1;
				musElementList_.at(lastPlayableIdx);
				switch (lastPlayable->getType()) {
					case T_CHORD: 
						     while (len1 >= MULTIPLICATOR) {
						     	newChord = ((NChord *) lastPlayable)->clone();
						        len = quant(len1, &dotcount, DOUBLE_WHOLE_LENGTH);
						        newChord->changeLength(len);
						        newChord->setDotted(dotcount);
						        noteList = newChord->getNoteList();
						        for (note = noteList->first(); note; note = noteList->next()) {
								  note->status |= STAT_TIED;
						        }
						        musElementList_.insert(lastPlayableIdx, newChord);
						        for (note = noteList->first(); note; note = noteList->next()) {
								reconnectTies(note);
						        }
						        for (note = noteList->first(); note; note = noteList->next()) {
								findTieMember(note);
						        }
							lastPlayableIdx++;
							len1 -= newChord->getMidiLength();
						     }
						     musElementList_.insert(lastPlayableIdx, elem);
						     lastPlayableIdx++;
						     while (len2 >= MULTIPLICATOR) {
						        len = quant(len2, &dotcount, DOUBLE_WHOLE_LENGTH);
							restlen  = len2 - (dotcount ? 3 * len / 2 : len);
							if (restlen >= MULTIPLICATOR) {
						     		newChord = ((NChord *) lastPlayable)->clone();
							}
							else {
								newChord = (NChord *)lastPlayable;
							}
						        newChord->changeLength(len);
						        newChord->setDotted(dotcount);
							if (restlen > 2) {
						           noteList = newChord->getNoteList();
						           for (note = noteList->first(); note; note = noteList->next()) {
								  note->status |= STAT_TIED;
						           }
						           musElementList_.insert(lastPlayableIdx, newChord);
						           for (note = noteList->first(); note; note = noteList->next()) {
								reconnectTies(note);
						           }
						           for (note = noteList->first(); note; note = noteList->next()) {
								findTieMember(note);
						           }
							   lastPlayableIdx++;
							}
							len2 -= newChord->getMidiLength();
						     }
						     break;
					case T_REST: 
						     musElementList_.remove();
						     while (len1 >= MULTIPLICATOR) {
							len = quant(len1, &dotcount, WHOLE_LENGTH);
							newRest = new NRest(main_props_, &(theStaff_->staff_props_), &yRestOffs_, len, dotcount);
							musElementList_.insert(lastPlayableIdx, newRest);
							lastPlayableIdx++;
							len1 -= newRest->getMidiLength();
						     }
						     musElementList_.insert(lastPlayableIdx, elem);
						     lastPlayableIdx++;
						     while (len2 >= MULTIPLICATOR) {
							len = quant(len2, &dotcount, WHOLE_LENGTH);
							newRest = new NRest(main_props_, &(theStaff_->staff_props_), &yRestOffs_, len, dotcount);
							musElementList_.insert(lastPlayableIdx, newRest);
							lastPlayableIdx++;
							len2 -= newRest->getMidiLength();
						     }
						     break;
				}
			}
			else {
				idx = musElementList_.at();
				if (idx < 0) idx = 0;
				musElementList_.insert(idx, elem);
			}
			return;
		}
		if (el->getType() & PLAYABLE) {
			lastPlayable = (NRest *) el;
			lastPlayableIdx = musElementList_.at();
		}
	}
}			

void NVoice::handleEndAfterMidiImport(int difftime) {
	int len, dotcount;
	NRest *rest;

	while (difftime >= MULTIPLICATOR) {
		len = quant(difftime, &dotcount, WHOLE_LENGTH);
		rest = new NRest(main_props_, &(theStaff_->staff_props_), &yRestOffs_, len, dotcount);
		musElementList_.append(rest);
		difftime -= rest->getMidiLength();
	}
}

bool NVoice::insertElemAtTime(unsigned int at, NSign *sign, NMusElement *last_bar_sym) {
	int idx;

	if ((idx = findIdxOfNearestPlayableElem(last_bar_sym, at*MULTIPLICATOR)) == -1) return false;

	if (idx == -2) {
		musElementList_.append(sign);
		return true;
	}
	else {
		musElementList_.insert(idx, sign);
		musElementList_.last();
	}
	return true;
}

void NVoice::addLyrics(char *charlyrics, int verse) {
	int idx1, len1;
	int idx2, len2;
	bool found;
	NMusElement *elem;
	QString word;
	QString lyrics;

	found = false;
	elem = musElementList_.last();
	while (!found && elem) {
		if (!(found = (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)))) elem = musElementList_.prev();
	}
	if (!found) elem = musElementList_.first();
	if (!elem) {
		musElementList_.last();
		return;
	}
	lyrics = QString::fromUtf8(charlyrics);
	lyrics.replace(escapedApostroph_, "");
	idx1 = wordPattern1_.match(lyrics, 0, &len1, true); 
	if ((idx2 = wordPattern2_.match(lyrics, 0, &len2, true)) != -1) {
		if (idx2 <= idx1) {
			idx1 = idx2; len1 = len2;
		}
	}
	while (idx1 >= 0 && elem) {
		word = lyrics.mid(idx1, len1);
		found = false;
		while (!found && elem) {
			if (!(found = elem->getType() == T_CHORD &&
				 !(elem->getNoteList()->first()->status & STAT_PART_OF_TIE) && !(elem->status_ & STAT_GRACE))) {
					elem = musElementList_.next();
			}
		}
		if (!found) {
			musElementList_.last();
			return;
		}
		if (word != "<>") {
			((NChord *) elem)->setLyrics(&word, verse);
		}
		elem = musElementList_.next();
		lyrics.remove(0, idx1 + len1);
		idx1 = wordPattern1_.match(lyrics, 0, &len1, true); 
		if ((idx2 = wordPattern2_.match(lyrics, 0, &len2, true)) != -1) {
			if (idx2 <= idx1) {
				idx1 = idx2; len1 = len2;
			}
		}
	}
}

void NVoice::copyLyricsToEditor() {
    int i;
    NChord *chord;
    NMusElement *elem;
    QString *s;
    int length;
    for( i = 0; i < NUM_LYRICS; i++ ) {
	NResource::lyrics_[i].truncate(0);
    }
    for (i = 0; i < NUM_LYRICS; i++) {
	length = 0;
	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		if (elem->getType() != T_CHORD) continue;
		chord = (NChord *) elem;
		if (s = chord->getLyrics(i)) {
		   NResource::lyrics_[i] += *s;
		   if ((length += s->length()) > MAX_LINE_IN_EDITOR) {
		   	NResource::lyrics_[i].append('\n');
			length = 0;
		   }
		   else {
		   	NResource::lyrics_[i].append(' ');
		   }
		}
	}
    }
}
    

void NVoice::updateLyrics() {
    NMusElement *elem;
    QString word;
    int idx1, len1;
    int idx2, len2;

    for( int i = 0; i < NUM_LYRICS; i++ ) {
	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
	    if (elem->getType() != T_CHORD) continue;
	    ((NChord *) elem)->deleteLyrics(i);
	}
    }    

    for( int i = 0; i < NUM_LYRICS; i++ ) {
	if( !NResource::lyrics_[i].isEmpty() ) {
	    idx1 = wordPattern1_.match(NResource::lyrics_[i], 0, &len1, true);
	    if ((idx2 = wordPattern2_.match(NResource::lyrics_[i], 0, &len2, true)) != -1) {
		if (idx2 <= idx1) {
			idx1 = idx2; len1 = len2;
		}
	    }
	    elem = musElementList_.first();
	    while (elem  && idx1 >= 0) {
		if (elem->getType() != T_CHORD || (elem->getNoteList()->first()->status & STAT_PART_OF_TIE)
			||  (elem->status_ & STAT_GRACE)) {
			elem = musElementList_.next();
			continue;
		}
		word = NResource::lyrics_[i].mid(idx1, len1);
		((NChord *) elem)->setLyrics(&word, i);
		NResource::lyrics_[i].remove(0, idx1 + len1);
		idx1 = wordPattern1_.match(NResource::lyrics_[i], 0, &len1, true); 
		if ((idx2 = wordPattern2_.match(NResource::lyrics_[i], 0, &len2, true)) != -1) {
			if (idx2 <= idx1) {
				idx1 = idx2; len1 = len2;
			}
		}
		elem = musElementList_.next();
	    }
	}
   }
}

int NVoice::countOfLyricsLines() {
	int max = 0;
	NMusElement *elem;

	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		if (elem->getType() != T_CHORD) continue;
		if (((NChord *) elem)->countOfLyricsLines() > max)  max = ((NChord *) elem)->countOfLyricsLines();
	}
	return max;
}

void NVoice::collectLyrics(QString lyricslist[NUM_LYRICS]) {
	int i, length;
	NChord *chord;
	NMusElement *elem;
	QString *s;
	bool lyricsAdded[NUM_LYRICS];

	for (i = 0; i < NUM_LYRICS; i++) {
		lyricslist[i].truncate(0);
		lyricsAdded[i] = false;
	}
	for (i = 0; i < NUM_LYRICS; i++) {
		for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
			if (elem->getType() != T_CHORD) continue;
			chord = (NChord *) elem;
			if (s = chord->getLyrics(i)) {
				if (s->compare("-") == 0) {
					lyricslist[i] += ".";
					length ++;
				}
				else {
		   			lyricslist[i] += *s;
					length += s->length();
				}
				lyricsAdded[i] = true;
			}
			else {
		   		lyricslist[i].append(".");
				length += 3;
			}
			if (lyricslist[i].right(1).compare("-")) {
				lyricslist[i].append(" ");
				length++;
				if (length > MAX_LINE_IN_EDITOR) {
		   			lyricslist[i].append('\n');
					length = 0;
				}
		   	}
		}
	}
	for (i = 0; i < NUM_LYRICS; i++) {
		if (!lyricsAdded[i]) {
			lyricslist[i].truncate(0);
		}
	}
}

/*------------------------------- transposition -----------------------------------------*/

void NVoice::checkContext(int xpos) {
	NMusElement *elem;
	for (elem = musElementList_.first(); elem && elem->getXpos() < xpos; elem = musElementList_.next()) {
		switch(elem->getType()) {
		case T_CLEF: theStaff_->actualClef_.change((NClef *) elem);
			     theStaff_->actualKeysig_.setClef((NClef *) elem);
			     break;
		case T_KEYSIG: theStaff_->actualKeysig_.change((NKeySig *) elem);
				break;
		}
	}
}

void NVoice::transpose(int semitones, bool region) {
	NMusElement *elem, *elem1;
	NNote *note;
	NChord *chord;
	NRest *rest;
	int midi_pitch;
	int line, offs;
	int xpos0 = -1, xpos1 = -1;
	int idx0 = -1, idx1 = -1;
	QList<NNote> tied_notes;
	QList<NNote> part_of_tied_notes;

	theStaff_->actualClef_.change(NResource::nullClef_);
	if (region) {
	   if (startElement_ && endElement_) {
		if (endElementIdx_ > startElemIdx_) {
			xpos0 = startElement_->getXpos();
			xpos1 = endElement_->getXpos();
			idx0 = startElemIdx_;
			idx1 = endElementIdx_;
		}
		else {
			xpos0 = endElement_->getXpos();
			xpos1 = startElement_->getXpos();
			idx0 = endElementIdx_;
			idx1 = startElemIdx_;
		}
		if ((elem1 = elem = musElementList_.at(idx0)) == 0) {
			NResource::abort("NVoice::transpose: internal error", 1);
		}
		theStaff_->actualClef_.change(NResource::nullClef_);
		for (;elem1; elem1 = musElementList_.prev()) {
			if (elem1->getType() == T_CLEF) {
				theStaff_->actualClef_.change((NClef *) elem1);
				break;
			}
		}
		if ((elem = musElementList_.at(idx0)) == 0) {
			NResource::abort("NVoice::transpose: internal error", 2);
		}
		createUndoElement(idx0, idx1 - idx0 + 1, 0);
	   }
	   else {
		elem = musElementList_.first();
		createUndoElement(0, musElementList_.count(), 0);
	   }
	}
	else {
		elem = musElementList_.first();
		createUndoElement(0, musElementList_.count(), 0);
	}
        for (;elem && (idx0 <= idx1 || xpos1 == -1); elem = musElementList_.next(), idx0++) {
		if (!firstVoice_) theStaff_->checkContext(elem->getXpos());
		switch(elem->getType()) {
		case T_CHORD:
			chord = (NChord *) elem;
			for (note = chord->getNoteList()->first(); note; note = chord->getNoteList()->next()) {
				if (xpos1 != -1) {
					if (note->status & STAT_TIED) tied_notes.append(note);
					if (note->status & STAT_PART_OF_TIE) part_of_tied_notes.append(note);
				}
				midi_pitch = theStaff_->actualClef_.line2midiTab_[note->line+LINE_OVERFLOW]+note->offs+theStaff_->actualClef_.getShift();
				midi_pitch += semitones;
				theStaff_->actualClef_.midi2Line(midi_pitch, &line, &offs);
				if (line <= MAXLINE && line >= MINLINE) {
					note->line = line; note->offs = offs;
				}
			}
			chord->determineStemDir(stemPolicy_);
			if (chord->lastBeamed()) {
				NChord::computeBeames(chord->getBeamList(), stemPolicy_);
			}
			chord->transposeChordDiagram(semitones);
			break;
		case T_REST:
			rest = (NRest *)elem;
			rest->transposeChordDiagram(semitones);
			break;
		case T_CLEF:
			theStaff_->actualClef_.change((NClef *) elem); 
			break;
		}
	}
	if (xpos1 == -1) return;
	for (note = tied_notes.first(); note; note = tied_notes.next()) {
		if (note->tie_forward->chordref->getXpos() < xpos1) continue;
		if (note->tie_forward->status & STAT_VIRTUAL) {
			if (virtualChord_.find(note->tie_forward) != -1) {
				virtualChord_.remove();
			}
			else {
				NResource::abort("NVoice::transpose: internal error", 3);
			}
		}
		else {
			note->tie_forward->tie_backward = 0;
			note->tie_forward->status &= (~STAT_PART_OF_TIE);
		}
		note->status &= (~STAT_TIED);
	}
	for (note = part_of_tied_notes.first(); note; note = part_of_tied_notes.next()) {
		if (!(note->status & STAT_PART_OF_TIE)) continue;
		if (note->tie_backward->chordref->getXpos() >= xpos0) continue;
		findTieMember(note->tie_backward);
		note->tie_backward = 0;
		note->status &= (~STAT_PART_OF_TIE);
	}
}

void NVoice::combineChords(int firstIdx, int lastIdx) {
	int oldidx;
	NMusElement *elem;
	NChord *chord, *newChord;
	QList<NNote> *noteList, *noteList1, *noteList2;
	NChord *firstChord, *lastChord;
	NNote *note, *note1, *note2;
	bool first;
	bool endOfList = (lastIdx == musElementList_.count() - 1);
	int i, idx, dotcount;
	int MIDIlength = 0, newlen, len2, length = lastIdx - firstIdx + 1;
	oldidx = musElementList_.at();

	firstChord = (NChord *) musElementList_.at(firstIdx);
	lastChord = (NChord *) musElementList_.at(lastIdx);

	for (i = 0, elem = musElementList_.at(firstIdx); i < length; elem = musElementList_.next(), i++) {
		MIDIlength += elem->getMidiLength ();
	}
	noteList1 = firstChord->getNoteList();
	noteList2 = lastChord->getNoteList();
	i = 0; 
	chord = (NChord *) musElementList_.at(firstIdx);
	while (i < length) {
		if (chord->status_ & STAT_BEAMED) {
			chord->breakBeames();
		}
		if (chord->status_ & (STAT_SLURED | STAT_PART_OF_SLUR)) {
			chord->breakSlurConnections();
		}
		musElementList_.remove();
		i++;
	}
	first = true; idx = firstIdx;
	newlen = 0; idx = firstIdx;
	while (MIDIlength >= MULTIPLICATOR) {
		len2 = quant(MIDIlength, &dotcount, DOUBLE_WHOLE_LENGTH);
		MIDIlength -= dotcount ? 3 * len2 / 2 : len2;
		newChord = firstChord->clone();
		noteList = newChord->getNoteList();
		for (note = noteList->first(), note1 = noteList1->first(), note2 = noteList2->first(); note; 
			note = noteList->next(), note1 = noteList1->next(), note2 = noteList2->next()) {
			note->status = 0;
			if (first) {
				SET_STATUS ((note1->status & STAT_PART_OF_TIE), note->status, STAT_PART_OF_TIE);
			}
			else {
				note->status |= STAT_PART_OF_TIE;
			}
			if (MIDIlength < MULTIPLICATOR) {
				SET_STATUS ((note2->status & STAT_TIED), note->status, STAT_TIED);
			}
			else {
				note->status |= STAT_TIED;
			}
			first = false;
		}
		newChord->status_ = dotcount;
		SET_STATUS ((firstChord->status_ & STAT_STEM_UP_BEFORE_BEAM), newChord->status_, STAT_STEM_UP);
		SET_STATUS ((firstChord->status_ & STAT_STEM_UP_BEFORE_BEAM), newChord->status_, STAT_STEM_UP_BEFORE_BEAM);
		newChord->changeLength(len2);
		if (endOfList) {
			musElementList_.append(newChord);
		}
		else {
			musElementList_.insert(idx++, newChord);
		}
		newlen++;
	}
	chord = (NChord *) musElementList_.at(firstIdx);
	for (i = 0; i < newlen; chord = (NChord *) musElementList_.next(), i++) {
		handleChordTies(chord, i == newlen - 1);
	}
	delete firstChord;
        delete lastChord;
	setCountOfAddedItems(musElementList_.count());
	oldidx -= length;
	if (endOfList) {
		musElementList_.last();
	}
	else {
		musElementList_.at(oldidx);
	}
}

void NVoice::collChords() {
	NMusElement *elem;
	NChord *first = 0, *last, *chord, *chordBefore;
	int firstIdx, lastIdx;

	createUndoElement(0, musElementList_.count(), 0);
	if (!firstVoice_) {
		theStaff_->resetSpecialElement();
	}
	
	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		if (elem->getType() != T_CHORD) {
			if (first && firstIdx != lastIdx) {
				combineChords(firstIdx, lastIdx);
			}
			first = 0;
			continue;
		}
		if (!firstVoice_ && first && firstIdx != lastIdx) {
			if (theStaff_->checkSpecialElement(elem->getXpos())) {
				while (theStaff_->checkSpecialElement(elem->getXpos()));
				combineChords(firstIdx, lastIdx);
				first = 0;
				continue;
			}
		}
		chordBefore = chord;
		chord = (NChord *) elem;
		
		if (first) {
			if (chordBefore->equalTiedChord(chord)) {
				last = chord;
				lastIdx = musElementList_.at();
			}
			else if (firstIdx != lastIdx) {
				combineChords(firstIdx, lastIdx);
				chordBefore = first = chord;
				firstIdx = lastIdx = musElementList_.at();
			}
			else {
				chordBefore = first = chord;
				firstIdx = lastIdx = musElementList_.at();
			}
		}
		else {
			chordBefore = first = chord;
			firstIdx = lastIdx = musElementList_.at();
			if (!firstVoice_) {
				theStaff_->syncSpecialElement(chord->getXpos());
			}
		}
	}
	if (first && firstIdx != lastIdx) {
		combineChords(firstIdx, lastIdx);
	}
}

/*------------------------------- clef change  -----------------------------------------*/

void NVoice::performClefChange(int type, int shift, bool region, int *dist, int *stop_x) {
	NMusElement *elem, *elem_before = 0, *elem1;
	NNote *note;
	int line;
	bool stop_working = false, chord_seen = false;
	int xpos0 = -1, xpos1 = -1;
	int idx0 = -1, idx1 = -1;
	int dd = 0;
	QList<NNote> tied_notes;
	QList<NNote> part_of_tied_notes;
	NClef clef(main_props_, &(theStaff_->staff_props_));

	if (*dist != UNDEFINED_DIST) dd = *dist;
	
	theStaff_->actualClef_.change(NResource::nullClef_);
	if (region) {
	   if (startElement_ && endElement_) {
		if (endElementIdx_ > startElemIdx_) {
			xpos0 = startElement_->getXpos();
			xpos1 = endElement_->getXpos();
			idx0 = startElemIdx_;
			idx1 = endElementIdx_;
		}
		else {
			xpos0 = endElement_->getXpos();
			xpos1 = startElement_->getXpos();
			idx0 = endElementIdx_;
			idx1 = startElemIdx_;
		}
		if ((elem1 = elem = musElementList_.at(idx0)) == 0) {
			NResource::abort("NVoice::performClefChange: internal error", 1);
		}
		theStaff_->actualClef_.change(NResource::nullClef_);
		for (;elem1; elem1 = musElementList_.prev()) {
			if (elem1->getType() == T_CLEF) {
				theStaff_->actualClef_.change((NClef *) elem1);
				break;
			}
		}
		if ((elem = musElementList_.at(idx0)) == 0) {
			NResource::abort("NVoice::performClefChange: internal error", 2);
		}
		createUndoElement(idx0, idx1 - idx0 + 1, 0);
	   }
	   else {
		elem = musElementList_.first();
		createUndoElement(0, musElementList_.count(), 0);
	   }
	}
	else {
		elem = musElementList_.first();
		createUndoElement(0, musElementList_.count(), 0);
	}
        for (;elem && (*stop_x > elem->getXpos()) && (idx0 <= idx1 || xpos1 == -1) && !stop_working; elem_before = elem, elem = musElementList_.next(), idx0++) {
		switch(elem->getType()) {
		case T_CHORD:
			chord_seen = true;
			for (note = elem->getNoteList()->first(); note; note = elem->getNoteList()->next()) {
				if (xpos1 != -1) {
					if (note->status & STAT_TIED) tied_notes.append(note);
					if (note->status & STAT_PART_OF_TIE) part_of_tied_notes.append(note);
				}
				line = note->line + dd;
				while (line > MAXLINE) line -= 7;
				while (line < MINLINE) line += 7;
				note->line = line; 
			}
			((NChord *) elem)->determineStemDir(stemPolicy_);
			break;
		case T_CLEF:
			if (chord_seen) {
				stop_working = true;
				if (stop_x) *stop_x = elem->getXpos();
				break;
			}
			clef = NClef(main_props_, &(theStaff_->staff_props_), type, shift);
			dd = clef.lineOfC4() - ((NClef *) elem)->lineOfC4();
			if (*dist == UNDEFINED_DIST) *dist = dd;
			((NClef *) elem)->change(&clef);
			theStaff_->actualClef_.change(&clef);
			break;
		case T_KEYSIG: ((NKeySig *) elem)->setClef(&theStaff_->actualClef_);
			break;
		}
	}
	if (xpos1 == -1) return;
	for (note = tied_notes.first(); note; note = tied_notes.next()) {
		if (note->tie_forward->chordref->getXpos() < xpos1) continue;
		if (note->tie_forward->status & STAT_VIRTUAL) {
			if (virtualChord_.find(note->tie_forward) != -1) {
				virtualChord_.remove();
			}
			else {
				NResource::abort("NVoice::transpose: internal error", 3);
			}
		}
		else {
			note->tie_forward->tie_backward = 0;
			note->tie_forward->status &= (~STAT_PART_OF_TIE);
		}
		note->status &= (~STAT_TIED);
	}
	for (note = part_of_tied_notes.first(); note; note = part_of_tied_notes.next()) {
		if (!(note->status & STAT_PART_OF_TIE)) continue;
		if (note->tie_backward->chordref->getXpos() >= xpos0) continue;
		findTieMember(note->tie_backward);
		note->tie_backward = 0;
		note->status &= (~STAT_PART_OF_TIE);
	}
}
		

/* only called in grammar.yy and musicxmlimport.cpp          */
/* the MusicXML importer requires the ability to build beams */
/* that cross signs, except barsyms                          */
bool NVoice::buildBeam(NMusElement *elem0, NMusElement *elem1) {
	bool found = false;
	QList<NChord> *beamlist;
	NChord *chord, *prevchord = 0;

	if (musElementList_.find(elem1) == -1) return false;
	if (musElementList_.find(elem0) == -1) return false;
	beamlist = new QList<NChord>();
	while (!found && elem0 != 0) {
		found = elem0 == elem1;
		if (elem0->getType() == T_CHORD) {
			if (elem0->getSubType() >= QUARTER_LENGTH || (elem0->status_ & STAT_BEAMED)) {
				delete beamlist;
				return false;
			}
			chord = (NChord *) elem0;
			if (prevchord != 0) {
				prevchord->setBeamParams(beamlist, chord, 0.0, 1.0);
			}
			beamlist->append(chord);
			prevchord = chord;
			elem0 = musElementList_.next();
		}
		else if (elem0->getType() == T_REST) {
			elem0 = musElementList_.next();
		}
		else if (elem0->getType() == T_SIGN) {
			// disallow barsyms
			if ((elem0->getSubType()) & BAR_SYMS) {
				delete beamlist;
				return false;
			}
			// but ignore all others
			elem0 = musElementList_.next();
		}
		else {
			delete beamlist;
			return false;
		}
	}
	chord = (NChord *) elem1;
	chord->setBeamParams(beamlist, 0, 0.0, 1.0);
	if (!found || beamlist->count() < 2) {
		delete beamlist;
		return false;
	}
	/* set STAT_STEM_UP_BEFORE_BEAM so that after beam break */
	/* the standard rules apply				 */
	for (chord = beamlist->first(); chord; chord = beamlist->next()) {
		chord->computeStemBefore();
	}
	NChord::computeBeames(beamlist, stemPolicy_);
	return true;
}

void NVoice::appendElem(int el_type, int line, int sub_type, int offs, unsigned int status) {
	NMusElement *new_elem;
	NNote *note;
	NTimeSig *timesig;
	NKeySig *tmpkeysig;
	NClef *tmpclef;
	bool is_chord = false;

	switch (el_type) {
		case T_CHORD:
			is_chord = true;
			new_elem = new NChord(main_props_, &(theStaff_->staff_props_), line, offs, sub_type, stemPolicy_, status);
			note = new_elem->getNoteList()->first();
			break;
		case T_REST:
			new_elem = 
			new NRest(main_props_, &(theStaff_->staff_props_), &yRestOffs_, sub_type, status);
			break;
		case T_SIGN:
			new_elem =
			new NSign(main_props_, &(theStaff_->staff_props_), sub_type);
			break;
		case T_CLEF: tmpclef = new NClef(main_props_, &(theStaff_->staff_props_));
			     tmpclef->change(&(theStaff_->actualClef_));
			     tmpclef->setStaffProps(&(theStaff_->staff_props_));
			     new_elem = tmpclef;
			break;
		case T_KEYSIG:
			tmpkeysig = new NKeySig(main_props_, &(theStaff_->staff_props_));
			tmpkeysig->change(&(theStaff_->actualKeysig_));
			tmpkeysig->setStaffProps(&(theStaff_->staff_props_));
			tmpkeysig->setClef(&(theStaff_->actualClef_));
			tmpkeysig->reposit(0, 0);
			theStaff_->actualKeysig_ = *tmpkeysig;
			new_elem = tmpkeysig;
			break;
		case T_TIMESIG:
			timesig = new NTimeSig(main_props_, &(theStaff_->staff_props_));
			timesig->setSignature(line, sub_type);
			new_elem = timesig;
			break;
		default: NResource::abort("unknown music element");
	}
	musElementList_.append(new_elem);
	if (is_chord) {
		reconnectFileReadTies(note);
		if (status & STAT_TIED) {
			findTieMember(note);
		}
	}
}

void NVoice::appendElem(NMusElement *elem) {
	QList<NNote> *noteList;
	NNote *note;
	NChord *chord;
	musElementList_.append(elem);
	if (elem->getType() == T_CHORD) {
		chord = (NChord *) elem;
		noteList = chord->getNoteList();
		for (note = noteList->first(); note; note = noteList->next()) {
			reconnectFileReadTies(note);
			if (note->status & STAT_TIED) {
				findTieMember(note);
			}
		}
	}
}

int NVoice::getBarsymTimeBefore(int till_meascount, int miditime) {
	NMusElement *elem;
	int actualmiditime = 0;
	int lastbarsymtime = 0;
	for (elem =  musElementList_.first(); elem && actualmiditime <= miditime; elem =  musElementList_.next()) {
		actualmiditime += elem->getMidiLength();
		if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
			lastbarsymtime = actualmiditime;
		}
	}
	while (till_meascount > 0 && elem) {
		for (;till_meascount > 0 && elem; elem = musElementList_.next()) {
			actualmiditime += elem->getMidiLength();
			if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
				till_meascount--;
			}
		}
		if (!elem) {
			NResource::abort("NVoice::getBarsymTimeBefore", 1);
		}
		lastbarsymtime = actualmiditime;
	}
	return lastbarsymtime;
}


NChord *NVoice::findChordAt(NMusElement *from, int mididist) {
	bool minimum_set = false;
	int diff, mindist = (1 << 30);
	NMusElement *elem;
	NChord *nearestchord = 0;
	int actualmiditime, timeOfLastBarsym;
	bool found;


	if (!firstVoice_) {
		actualmiditime = 0;
		for (elem =  musElementList_.first(); elem && elem != from; elem =  musElementList_.next()) {
			actualmiditime += elem->getMidiLength();
		}
		timeOfLastBarsym = theStaff_->getVoiceNr(0)->getBarsymTimeBefore(0, actualmiditime);
		actualmiditime = 0;
		for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
			if (actualmiditime >= timeOfLastBarsym) break;
			actualmiditime += elem->getMidiLength();
		}
		if (from) {
			found = false;
			for (; elem; elem = musElementList_.next()) {
				actualmiditime += elem->getMidiLength();
				if (found) break;
				if (elem == from) found = true;
			}
		}
		if (!elem) return 0;
		if (timeOfLastBarsym == actualmiditime) {
			actualmiditime = 0;
		}
		else {
			actualmiditime = elem->getMidiLength();
		}
	}
	else {
		if (from == 0) {
			if ((elem = musElementList_.first()) == 0) return 0;
		}
		else {
			if (musElementList_.find(from) == -1) return 0;
		}
		actualmiditime = 0;
		elem = musElementList_.next();
	}
	found = false;
	while (!found && elem)  {
		if (elem->getType() == T_CHORD /* && !(elem->status_ & STAT_GRACE )*/) {
			diff = actualmiditime - mididist;
			if (diff < 0) diff = -diff;
			if (mindist > diff) {
				mindist = diff;
				minimum_set = true;
				nearestchord = (NChord *) elem;
			}
			else if (minimum_set) {
				found = true;
			}
		}
		actualmiditime += elem->getMidiLength();
		elem = musElementList_.next();
	}
	return nearestchord;
}

NChord *NVoice::findChordInMeasureAt(int refpoint, NMusElement *from, int till_meascount, int mididist) {
	bool found = false, minimum_set = false;
	int diff, mindist = (1 << 30);
	NMusElement *elem;
	NChord *nearestchord = 0;
	int actualmiditime, timeOfLastBarsym;
	int idx_of_last_bar_sym;


	if (!firstVoice_) {
		actualmiditime = 0;
		for (elem =  musElementList_.first(); elem && elem != from; elem =  musElementList_.next()) {
			actualmiditime += elem->getMidiLength();
		}
		timeOfLastBarsym = theStaff_->getVoiceNr(0)->getBarsymTimeBefore(till_meascount, actualmiditime);
		actualmiditime = 0;
		for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
			actualmiditime += elem->getMidiLength();
			if (actualmiditime > timeOfLastBarsym) break;
		}
		if (!elem) return 0;
		actualmiditime = 0;
	}
	else {
		if (from == 0) {
			if ((elem = musElementList_.first()) == 0) return 0;
			actualmiditime = 0;
		}
		else {
			actualmiditime = 0;
			timeOfLastBarsym = 0;
			idx_of_last_bar_sym = -1;
			for (elem = musElementList_.first(); elem && elem != from; elem = musElementList_.next()) {
				actualmiditime += elem->getMidiLength();
				if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
					timeOfLastBarsym = actualmiditime;
					idx_of_last_bar_sym = musElementList_.at();
				}
			}
			if (elem == 0) {
				return 0;
			}
			if (idx_of_last_bar_sym < 0) {
				if ((elem = musElementList_.first()) == 0) return 0;
			}
			else {
				elem = musElementList_.at(idx_of_last_bar_sym);
			}
			actualmiditime = 0;
		}
		if (till_meascount > 0) {
			for (elem = musElementList_.next();till_meascount > 0 && elem; elem = musElementList_.next()) {
				if (elem->getType() == T_SIGN && (elem->getSubType() & BAR_SYMS)) {
					till_meascount--;
				}
			}
			actualmiditime = 0;
		}
		if (!elem) {
			NResource::abort("NVoice::findChordInMeasureAt", 1);
		}

	}
			
	while (!found && elem)  {
		if (elem->getType() == T_CHORD && !(elem->status_ & STAT_GRACE )) {
			diff = actualmiditime - mididist;
			if (diff < 0) diff = -diff;
			if (mindist > diff) {
				mindist = diff;
				minimum_set = true;
				nearestchord = (NChord *) elem;

			}
			else if (minimum_set) {
				found = true;
			}
		}
		actualmiditime += elem->getMidiLength();
		elem = musElementList_.next();
	}
	if (!found) {
		for (elem = musElementList_.last(); !found && elem && elem->getXpos() > refpoint; elem = musElementList_.prev()) {
			if (elem->getType() == T_CHORD && !(elem->status_ & STAT_GRACE )) {
				found = true;
				nearestchord = (NChord *) elem;
			}
		}
	}
	return nearestchord;
}

int NVoice::findIdxOfNearestPlayableElem(NMusElement *from, int mididist) {
	NMusElement *elem;
	bool found = false, minimum_set = false;
	int diff, mindist = (1 << 30);
	int actualmiditime;
	int idx, minidx = -1;

	if (from == 0) {
		if ((elem = musElementList_.first()) == 0) return -1;
		actualmiditime = 0;
	}
	else {
		if (musElementList_.find(from) == -1) return -1;
		actualmiditime = from->getMidiLength();
	}
	elem = musElementList_.next();
	while (!found && elem)  {
		if (!(elem->getType() & PLAYABLE)) {elem = musElementList_.next(); continue;}
		diff = actualmiditime - mididist;
		if (diff < 0) diff = -diff;
		if (mindist > diff) {
			idx = musElementList_.at();
			if (idx >= 0) {
				mindist = diff;
				minimum_set = true;
				minidx = idx;
			}
		}
		else if (mindist != diff && minimum_set) {
			found = true;
		}
		actualmiditime += elem->getMidiLength();
		elem = musElementList_.next();
	}
	if (!found) {
		diff = actualmiditime - mididist;
		if (diff < 0) diff = -diff;
		if (mindist > diff) {
			return -2;
		}
	}
	return minidx;
}
int NVoice::findIdxOfNearestElem(NMusElement *from, int mididist) {
	NMusElement *elem;
	bool found = false, minimum_set = false;
	int diff, mindist = (1 << 30);
	int actualmiditime;
	int idx, minidx = -1;

	if (from == 0) {
		if ((elem = musElementList_.first()) == 0) return -1;
		actualmiditime = 0;
	}
	else {
		if (musElementList_.find(from) == -1) return -1;
		actualmiditime = from->getMidiLength();
	}
	elem = musElementList_.next();
	while (!found && elem)  {
		diff = actualmiditime - mididist;
		if (diff < 0) diff = -diff;
		if (mindist > diff) {
			idx = musElementList_.at();
			if (idx >= 0) {
				mindist = diff;
				minimum_set = true;
				minidx = idx;
			}
		}
		else if (mindist != diff && minimum_set) {
			found = true;
		}
		actualmiditime += elem->getMidiLength();
		elem = musElementList_.next();
	}
	if (!found) {
		diff = actualmiditime - mididist;
		if (diff < 0) diff = -diff;
		if (mindist > diff) {
			return -2;
		}
	}
	return minidx;
}

NMusElement *NVoice::findChordOrRestAt(NMusElement *from, int mididist) {
	bool found = false, minimum_set = false;
	int diff, mindist = (1 << 30);
	NMusElement *elem;
	NMusElement *nearestelem = 0;
	int actualmiditime = 0;

	if (from == 0) {
		if (musElementList_.first() == 0) return 0;
	}
	else {
		if (musElementList_.find(from) == -1) return 0;
		actualmiditime += from->getMidiLength();
	}
	elem = musElementList_.next();
	while (!found && elem)  {
		if (elem->getType() == T_REST || elem->getType() == T_CHORD && !(elem->status_ & STAT_GRACE)) {
			diff = actualmiditime - mididist;
			if (diff < 0) diff = -diff;
			if (mindist > diff) {
				mindist = diff;
				minimum_set = true;
				nearestelem =  elem;
			}
			else if (minimum_set) {
				found = true;
			}
		}
		actualmiditime += elem->getMidiLength();
		elem = musElementList_.next();
	}
	return nearestelem;
}

void NVoice::correctReadTrillsSlursAndDynamicsAndVAs() {
	NMusElement *elem;
	NChord *chord1, *chord2;
	int pos1;
	int sign = 1;
	int xpos1, xpos2;
	int dist;
	unsigned int till_meascount;
	char *err = "correctReadTrillsSlursAndDynamicsAndVAs: internal error";
	for (elem = musElementList_.first(); elem; elem = musElementList_.next()) {
		if (elem->getType() != T_CHORD) continue;
		chord1 = (NChord *) elem;
		if (chord1->trill_) {
			dist = MULTIPLICATOR * (chord1->trill_ & 0x7fff);
			till_meascount = (chord1->trill_ >> 16);
			sign = (chord1->trill_ & 0x8000) ? -1 : 1;
			pos1 = musElementList_.at();
			xpos1 = chord1->getXpos();
			chord2 = findChordInMeasureAt(chord1->getXpos(), chord1, till_meascount, dist);
			if (chord2 == 0) {
				NResource::abort(err, 1);
			}
			xpos2 = chord2->getXpos();
			if (xpos2 < xpos1) xpos2 = xpos1;
			chord1->trill_ = sign * ((xpos2 - xpos1) / NResource::trillPixmap_->width() + 1);
			musElementList_.at(pos1);
		}
		if (chord1->va_) {
			dist = MULTIPLICATOR * (chord1->va_ & 0x7fff);
			till_meascount = (chord1->va_ >> 16);
			sign = (chord1->va_ & 0x8000) ? -1 : 1;
			pos1 = musElementList_.at();
			xpos1 = chord1->getXpos();
			chord2 = findChordInMeasureAt(chord1->getXpos(), chord1, till_meascount, dist);
			if (chord2 == 0) {
				NResource::abort(err, 2);
			}
			xpos2 = chord2->getXpos();
			if (xpos2 < xpos1) xpos2 = xpos1;
			if (sign > 0) {
				chord1->va_ = (xpos2 - xpos1 - VA_LINE_DASH_LEN) / VA_LINE_LEN + 1;
			}
			else {
				chord1->va_ = -((xpos2 - xpos1 - VA_LINE_DASH_LEN) / VA_LINE_LEN);
			}
			musElementList_.at(pos1);
		}
		if (chord1->dynamic_) {
			dist = MULTIPLICATOR * (chord1->dynamic_ & 0xffff);
			if (dist < 0) {
				NResource::abort(err, 3);
			}
			till_meascount = (chord1->dynamic_ >> 16);
			pos1 = musElementList_.at();
			xpos1 = chord1->getXpos();
			chord2 = findChordInMeasureAt(chord1->getXpos(), chord1, till_meascount, dist);
			if (chord2 == 0) {
				NResource::abort(err, 4);
			}
			xpos2 = chord2->getBbox()->right();
			chord1->dynamic_ = xpos2 - xpos1;
			musElementList_.at(pos1);
		}
		if (chord1->auxInfo_.provSlur_) {
			dist = MULTIPLICATOR * (chord1->auxInfo_.provSlur_ & 0xffff);
			till_meascount = (chord1->auxInfo_.provSlur_ >> 16);
			pos1 = musElementList_.at();
			chord2 = findChordInMeasureAt(chord1->getXpos(), chord1, till_meascount, dist);
			if (chord2 == 0) {
				NResource::abort(err, 5);
			}
			chord1->setSlured(true, chord2);
			musElementList_.at(pos1);
		}
	}
}

bool NVoice::setProvisionalTrill(int kind, unsigned int at, unsigned int till_meascount, unsigned int till, NMusElement *last_bar_sym) {
	NChord *chord;

	if ((chord = findChordAt(last_bar_sym, at*MULTIPLICATOR)) == 0) return false;

	if (till - at < 3 && till_meascount < 1) {
		chord->trill_ = (kind != NORMAL_TRILL) ? (1 | 0x8000) : 1;
		return true;
	}
	
	chord->trill_ = till;
	if (kind != NORMAL_TRILL) {
		chord->trill_ |= 0x8000;
	}
	chord->trill_ |= (till_meascount << 16);
	return true;
}

bool NVoice::setProvisionalOctaviation(int kind, unsigned int at, unsigned int till_meascount, unsigned int till, NMusElement *last_bar_sym) {
	NChord *chord;

	if ((chord = findChordAt(last_bar_sym, at*MULTIPLICATOR)) == 0) return false;

	if (till - at < 3 && till_meascount < 1) {
		chord->va_ = (kind != OCTAVIATION1P) ? (1 | 0x8000) : 1;
		return true;
	}
	
	chord->va_ = till;
	if (kind != OCTAVIATION1P) {
		chord->va_ |= 0x8000;
	}
	chord->va_ |= (till_meascount << 16);
	return true;
}

bool NVoice::setProvisionalSlur(unsigned int at, unsigned int till_meascount, unsigned int till, NMusElement *last_bar_sym) {
	NChord *chord;

	if ((chord = findChordAt(last_bar_sym, at*MULTIPLICATOR)) == 0) return false;

	if (till - at < 3 && till_meascount < 1) {
		chord->auxInfo_.provSlur_ = 1;
	}
	
	chord->auxInfo_.provSlur_ = till;
	chord->auxInfo_.provSlur_ |= (till_meascount << 16);
	return true;
}

bool NVoice::setProvisionalDynamic(int kind, unsigned int at, unsigned int till_meascount, unsigned int till, NMusElement *last_bar_sym) {
	NChord *chord;

	if ((chord = findChordAt(last_bar_sym, at*MULTIPLICATOR)) == 0) return false;
	
	chord->dynamicAlign_ = kind == DYN_DECRESCENDO;
		
	chord->dynamic_ = till;
	chord->dynamic_ |= (till_meascount << 16);
	return true;
}

bool NVoice::setReadArpeggio(unsigned int at, NMusElement *last_bar_sym) {
	NChord *chord;

	if ((chord = findChordAt(last_bar_sym, at*MULTIPLICATOR)) == 0) return false;
	
	chord->setArpeggio(true);
	return true;
}

bool NVoice::setReadPedalOn(unsigned int at, NMusElement *last_bar_sym) {
	NChord *chord;

	if ((chord = findChordAt(last_bar_sym, at*MULTIPLICATOR)) == 0) return false;
	
	chord->setPedalOn(true);
	return true;
}

bool NVoice::setReadPedalOff(unsigned int at, NMusElement *last_bar_sym) {
	NChord *chord;

	if ((chord = findChordAt(last_bar_sym, at*MULTIPLICATOR)) == 0) return false;
	
	chord->setPedalOff(true);
	return true;
}

bool NVoice::insertChordDiagrammAt(unsigned int at, NChordDiagram *diag, NMusElement *last_bar_sym) {
	NMusElement *elem;

	if ((elem = findChordOrRestAt(last_bar_sym, at*MULTIPLICATOR)) == 0) return false;
		
	elem->addChordDiagram(diag);
	return true;
}

bool NVoice::insertSegnoRitardAndAccelAt(unsigned int at, int type, NMusElement *last_bar_sym) {
	NSign *sign;
	int idx;
	if ((idx = findIdxOfNearestElem(last_bar_sym, at*MULTIPLICATOR)) == -1) return false;
	
	sign = new NSign(main_props_, &(theStaff_->staff_props_), type);
	if (idx == -2) {
		musElementList_.append(sign);
	}
	else {
		musElementList_.insert(idx, sign);
		musElementList_.last();
	}
	return true;
}

void NVoice::setHalfsAccordingKeySig() {
	NMusElement *elem;
	NKeySig *keysig = NResource::nullKeySig_;
	NNote *note;
	NClef *clef;
	QList<NNote> *noteList;

	createUndoElement(0, musElementList_.count(), 0);

	for (elem =  musElementList_.first(); elem; elem = musElementList_.next()) {
		if (!firstVoice_) theStaff_->checkContext(elem->getXpos());
		switch (elem->getType()) {
			case T_CLEF: clef = (NClef*) elem; break;
			case T_KEYSIG: keysig = (NKeySig *) elem;
				       keysig->setClef(clef);
				     break;
			case T_CHORD: if (!keysig) break;
				     noteList = elem->getNoteList();			
				     for (note = noteList->first(); note; note = noteList->next()) {
					keysig->changeHalfTone(note);
					note->status &= (~STAT_FORCE);
				     }
				     break;
		}
	}
}

void NVoice::setHalfsTo(int type, bool region) {
	NMusElement *elem;
	NNote *note;
	QList<NNote> *noteList;
	int xpos0 = -1, xpos1 = -1;
	int idx0 = -1, idx1 = -1;

        if (region) {
	   if (startElement_ && endElement_) {
		if (endElementIdx_ > startElemIdx_) {
			xpos0 = startElement_->getXpos();
			xpos1 = endElement_->getXpos();
			idx0 = startElemIdx_;
			idx1 = endElementIdx_;
		}
		else {
			xpos0 = endElement_->getXpos();
			xpos1 = startElement_->getXpos();
			idx0 = endElementIdx_;
			idx1 = startElemIdx_;
		}
		if ((elem = musElementList_.at(idx0)) == 0) {
			 NResource::abort(" NVoice::setHalfsTo: internal error", 1);
		}
		createUndoElement(idx0, idx1 - idx0 + 1, 0);
	   }
	   else {
		elem = musElementList_.first();
		createUndoElement(0, musElementList_.count(), 0);
	   }
	}
	else {
		elem = musElementList_.first();
		createUndoElement(0, musElementList_.count(), 0);
	}
        for (;elem && (idx0 <= idx1 || xpos1 == -1); elem = musElementList_.next(), idx0++) {
		switch (elem->getType()) {
			case T_CHORD: noteList = elem->getNoteList();			
				     for (note = noteList->first(); note; note = noteList->next()) {
					if (note->offs == 1 && type == STAT_FLAT) {
						note->line++; note->offs = -1;
					}
					else if (note->offs == -1 && type == STAT_CROSS) {
						note->line--; note->offs = 1;
					}
				     }
				     break;
		}
	}
}
	

/*---------------------------------- undo ---------------------------------------*/


void NVoice::pasteAtIndex(QList<NMusElement> *clipBoard, int idx) {
	int oldidx;
	NMusElement *ac_elem;
	NChord *chord;
	bool lastelem = (idx >= (int) musElementList_.count());

	oldidx = musElementList_.at();
	if (currentElement_)  {
		currentElement_->setActual(false);
		currentElement_->draw();
		currentElement_ = 0;
	}
	for (ac_elem = clipBoard->first(); ac_elem; ac_elem = clipBoard->next()) {
		ac_elem->setStaffProps(&(theStaff_->staff_props_));
		ac_elem->setActual(false);
		currentElement_ = ac_elem;
		if (lastelem) {
			musElementList_.append(ac_elem);
		}
		else {
			musElementList_.insert(idx, ac_elem);
			idx++;
		}
		switch (ac_elem->getType()) {
			case T_KEYSIG: ((NKeySig *) ac_elem)->setClef(&(theStaff_->actualClef_));
					break;
			case T_CHORD: chord = (NChord *) ac_elem;
				     reconnectCopiedTies(chord);
				     if (chord->lastBeamed()) {
				     		reconnectBeames();
				     }
			case T_REST:
				     if (ac_elem->status_ & STAT_LAST_TUPLET) {
						reconnectTuplets();
				     }
				     break;
		}
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
}	

void NVoice::deleteRange(int startpos, int numelements, int newitems, int reason) {
	int oldidx;
	NNote *note;
	QList<NNote> *noteList;
	NMusElement *ac_elem;
	NChord *chord;

	oldidx = musElementList_.at();
	if (currentElement_) {
		currentElement_->setActual(false);
	}
	createUndoElement(startpos, numelements, newitems, reason);
	if (numelements) {
		ac_elem = musElementList_.at(startpos);
		currentElement_ = 0;
	}
	
	while (numelements-- && ac_elem) {
		if (ac_elem->getType() == T_CHORD) {
			chord = (NChord *) ac_elem;
			chord->checkSlures();
			musElementList_.remove();
			noteList = chord->getNoteList();
			for (note = noteList->first(); note; note = noteList->next()) {
				reconnectDeletedTies(note);
			}
		}
		else {
			musElementList_.remove();
			ac_elem = musElementList_.current();
		}
		ac_elem = musElementList_.current();
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
}

NVoice *NVoice::undoPossible() {
	if (undocounter_  < 1) return 0;
	return undoelem_[(undoptr_+MAXUNDO - 1) % MAXUNDO].ref;
}

NVoice *NVoice::redoPossible() {
	if (redocounter_  < 1) return 0;
	return redoelem_[(redoptr_+MAXUNDO - 1) % MAXUNDO].ref;
}



QList<NMusElement> *NVoice::cloneGroup(int firstidx, int lastidx) {
	bool found = false;
	NMusElement *elem, *lastelem, *cloneelem;
	NChord *slurpartner = 0, *chord, *slured_chord;
	QList<NChord> *clonebeamlist = 0;
	QList<NMusElement> *clonelist;
	char *err = "cloneGroup: internal error";

	if (lastidx < firstidx) return 0;
	clonelist = new QList<NMusElement>();
	lastelem = musElementList_.at(lastidx);
	elem = musElementList_.at(firstidx);
	if (elem == 0 || lastelem == 0) {
		NResource::abort( err, 1);
	}
	while (!found && elem) {
		clonelist->append(cloneelem = elem->clone());
		if (elem->getType() == T_CHORD) {
			chord = (NChord *) elem;
			if (chord == slurpartner) {
				if (slurpartner == 0) {
					NResource::abort( err, 2);
				}
				slured_chord->setSlured(true, (NChord *) cloneelem);
				slurpartner = 0;
			}
			if (chord->status_ & STAT_SLURED) {
				slured_chord = (NChord *) cloneelem;
				slurpartner = chord->getSlurPartner();
			}
			if (chord->status_ & STAT_BEAMED) {
				if (clonebeamlist == 0) {
					clonebeamlist = new QList<NChord>();
				}
				clonebeamlist->append((NChord *) cloneelem);
				if (chord->lastBeamed()) {
					NChord::computeBeames(clonebeamlist, stemPolicy_);
					clonebeamlist = 0;
				}
			}
		}
		found = elem == lastelem;
		elem = musElementList_.next();
	}
	if (!found) {
		NResource::abort( err, 3);
	}
	return clonelist;
}

void NVoice::undo() {
	int newitems;
	if (currentElement_) {
		currentElement_->setActual(false);
		currentElement_ = 0;
	}
	undoptr_ = (undoptr_ + MAXUNDO - 1) % MAXUNDO;
	undocounter_--;
	newitems = -undoelem_[undoptr_].num_of_replaced_items;
	if (undoelem_[undoptr_].backup_area != 0) {
		newitems += undoelem_[undoptr_].backup_area->count();
	}
	deleteRange(undoelem_[undoptr_].first_replaced_item, undoelem_[undoptr_].num_of_replaced_items, newitems, REASON_UNDO_DONE);
	if (undoelem_[undoptr_].backup_area != 0) {
		pasteAtIndex(undoelem_[undoptr_].backup_area, undoelem_[undoptr_].first_replaced_item);
	}
}

void NVoice::redo() {
	int newitems;
	if (currentElement_) {
		currentElement_->setActual(false);
		currentElement_ = 0;
	}
	redoptr_ = (redoptr_ + MAXUNDO - 1) % MAXUNDO;
	redocounter_--;
	newitems = -redoelem_[redoptr_].num_of_replaced_items;
	if (redoelem_[redoptr_].backup_area != 0) {
		newitems += redoelem_[redoptr_].backup_area->count();
	}
	deleteRange(redoelem_[redoptr_].first_replaced_item, redoelem_[redoptr_].num_of_replaced_items, newitems, REASON_REDO_DONE);
	if (redoelem_[redoptr_].backup_area != 0) {
		pasteAtIndex(redoelem_[redoptr_].backup_area, redoelem_[redoptr_].first_replaced_item);
	}
}

void NVoice::createUndoElement(NMusElement *startElement, int length, int count_of_added_items, int reason) {
	int idx, oldidx;
	oldidx = musElementList_.at();
	if ((idx = musElementList_.find(startElement)) == -1) {
		NResource::abort("createUndoElement(a): internal error");
	}
	createUndoElement(idx, length, count_of_added_items, reason);
	if (oldidx >= 0) musElementList_.at(oldidx);
}

void NVoice::createUndoElement(int startpos, int length, int count_of_added_items, int reason) {
	int oldidx;
	int oldidx1, minidx, maxidx, elemidx;
	int firstidx, lastidx;
	bool limits_changed;
	NMusElement *elem;
	NChord *chord;
	QList<NChord> *beamlist;
	QList<NMusElement> *tupletlist;
	minidx = startpos;
	maxidx = minidx + length - 1;
	char *err = "createUndoElement:: internal error";

	oldidx = musElementList_.at();
	if (length) {
	  do {
		limits_changed = false;
		elem = musElementList_.at(minidx);
		for (;length && elem; elem = musElementList_.next(), length--) {
			elemidx = musElementList_.at();
			if (elem->status_ & STAT_TUPLET) {
				oldidx1 = musElementList_.at();
				if (oldidx1 < 0) {
					NResource::abort(err, 1);
				}
				tupletlist = elem->getTupletList();
				firstidx = musElementList_.find(tupletlist->first());
				lastidx = musElementList_.find(tupletlist->last());
				if (firstidx < 0 || lastidx < 0) {
					NResource::abort(err, 2);
				}
				if (firstidx > elemidx) {
					NResource::abort(err, 3);
				}
				if (lastidx < elemidx) {
					NResource::abort(err, 4);
				}
				if (firstidx < minidx) {minidx = firstidx; limits_changed = true;}
				if (lastidx > maxidx) {maxidx = lastidx; limits_changed = true;}
				musElementList_.at(oldidx1);
			}
			if (elem->status_ & STAT_BEAMED) {
				oldidx1 = musElementList_.at();
				if (oldidx1 < 0) {
					NResource::abort(err, 5);
				}
				chord = (NChord *) elem;
				beamlist = chord->getBeamList();
				firstidx = musElementList_.find(beamlist->first());
				lastidx = musElementList_.find(beamlist->last());
				if (firstidx < 0 || lastidx < 0) {
					NResource::abort(err, 6);
				}
				if (firstidx > elemidx) {
					NResource::abort(err, 7);
				}
				if (lastidx < elemidx) {
					NResource::abort(err, 8);
				}
				if (firstidx < minidx) {minidx = firstidx; limits_changed = true;}
				if (lastidx > maxidx) {maxidx = lastidx; limits_changed = true;}
				musElementList_.at(oldidx1);
			}
			if (elem->status_ & STAT_SLURED) {
				oldidx1 = musElementList_.at();
				if (oldidx1 < 0) {
					NResource::abort(err, 9);
				}
				chord = (NChord *) elem;
				firstidx = musElementList_.find(chord);
				lastidx = musElementList_.find(chord->getSlurPartner());
				if (firstidx < 0 || lastidx < 0) {
					NResource::abort(err, 10);
				}
				if (firstidx > elemidx) {
					NResource::abort(err, 11);
				}
				if (lastidx < elemidx) {
					NResource::abort(err, 12);
				}
				if (firstidx < minidx) {minidx = firstidx; limits_changed = true;}
				if (lastidx > maxidx) {maxidx = lastidx; limits_changed = true;}
				musElementList_.at(oldidx1);
			}
			if (elem->status_ & STAT_PART_OF_SLUR) {
				oldidx1 = musElementList_.at();
				if (oldidx1 < 0) {
					NResource::abort(err, 9);
				}
				chord = (NChord *) elem;
				lastidx = musElementList_.find(chord);
				firstidx = musElementList_.find(chord->getSlurStart());
				if (firstidx < 0 || lastidx < 0) {
					NResource::abort(err, 10);
				}
				if (firstidx > elemidx) {
					NResource::abort(err, 11);
				}
				if (lastidx < elemidx) {
					NResource::abort(err, 12);
				}
				if (firstidx < minidx) {minidx = firstidx; limits_changed = true;}
				if (lastidx > maxidx) {maxidx = lastidx; limits_changed = true;}
				musElementList_.at(oldidx1);
			}
		}
		if (limits_changed) {
			length = lastidx - firstidx + 1;
		}
	   }
	   while (limits_changed);
	}
	if (length) {
		NResource::abort( err, 13);
	}
	if (reason == REASON_UNDO_DONE) {
		if (redocounter_ == MAXUNDO) {
			freeCloneGroup(redoelem_[redoptr_].backup_area);
		}
		redoelem_[redoptr_].backup_area = cloneGroup(minidx, maxidx);
		redoelem_[redoptr_].first_replaced_item = minidx;
		redoelem_[redoptr_].num_of_replaced_items = maxidx - minidx + 1 + count_of_added_items;
		redoelem_[redoptr_].ref = this;
		redoptr_ = (redoptr_ + 1) % MAXUNDO;
		if (++redocounter_  > MAXUNDO) redocounter_ = MAXUNDO;
	}
	else {
		if (reason == REASON_UNDO && redocounter_) {
			invalidateReUndo();
		}
		if (undocounter_ == MAXUNDO) {
			freeCloneGroup(undoelem_[undoptr_].backup_area);
		}
		undoelem_[undoptr_].backup_area = cloneGroup(minidx, maxidx);
		undoelem_[undoptr_].first_replaced_item = minidx;
		undoelem_[undoptr_].num_of_replaced_items = maxidx - minidx + 1 + count_of_added_items;
		undoelem_[undoptr_].ref = this;
		lastundoptr_ = undoptr_;
		undoptr_ = (undoptr_ + 1) % MAXUNDO;
		if (++undocounter_  > MAXUNDO) undocounter_ = MAXUNDO;
	}
	if (oldidx >= 0) musElementList_.at(oldidx);
}

void NVoice::invalidateReUndo(bool with_undo) {
	while (redocounter_ > 0) {
		redoptr_ = (redoptr_ + MAXUNDO - 1) % MAXUNDO;
		redocounter_--;
		freeCloneGroup(redoelem_[redoptr_].backup_area);
	}
	if (!with_undo) return;
	while (undocounter_ > 0) {
		undoptr_ = (undoptr_ + MAXUNDO - 1) % MAXUNDO;
		undocounter_--;
		freeCloneGroup(undoelem_[undoptr_].backup_area);
	}
}

void NVoice::deleteLastUndo() {
	undoptr_ = (undoptr_ + MAXUNDO - 1) % MAXUNDO;
	undocounter_--;
}

void NVoice::setCountOfAddedItems(int count_of_added_items) {
	undoelem_[lastundoptr_].num_of_replaced_items = count_of_added_items;
}


void NVoice::freeCloneGroup(QList<NMusElement> *group) {
	if (group == 0) return;
	group->setAutoDelete(true);
	group->clear();
	delete group;
}
