/****************************************************************************************/
/*											*/
/* 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 <qstring.h>
#include <qregexp.h>
#include <qspinbox.h>
#include <qcheckbox.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <ctype.h>
#include "staff.h"
#include "abcexport.h"
#include "uiconnect.h"
#include "keysig.h"
#include "timesig.h"
#include "mainframewidget.h"
#include "rest.h"
#include "chord.h"
#include "chorddiagram.h"
#include "layout.h"

#define ABC_ERR_IRREGULAER 1
#define ABC_ERR_DRUM_STAFF 2
#define ABC_ERR_TUPLET	   3
#define ABC_ERR_BRACE_NESTING 4
#define ABC_ERR_ONE_STAFF_BRACKET 5
#define ABC_ERR_VAS	   6


NABCExport::NABCExport() {
	int i;
#if GCC_MAJ_VERS > 2
	os_ = new ostringstream();
	for (i = 0; i < NUM_LYRICS; i++) {
		lyricsLine_[i] = new ostringstream();
	}
#else
	os_ = new ostrstream(buffer_, 128);
	for (i = 0; i < NUM_LYRICS; i++) {
		lyricsLine_[i] = new ostrstream(NResource::lyricsbuffer_[i], LYRICS_LINE_LENGTH);
	}
#endif
}

void NABCExport::exportStaffs(QString fname, QList<NStaff> *stafflist, int count_of_voices, exportFrm *expWin, NMainFrameWidget *mainWidget) {
	NStaff *staff_elem;
	NVoice *voice_elem;
	NClef *firstClef;
	badinfo *bad;
	int i, j, k;
	int voice_count;
	int current_time;
	bool something_written;
	bool ok;
	bool with_pedal_marks;
	double dval;
	NMusElement *last_elem;
	QRegExp reg = QRegExp("/100");
	QString s;

	out_.open(fname);
	if (!out_) {
		*os_ << "error opening file " << fname << '\0';
#if GCC_MAJ_VERS > 2
		KMessageBox::sorry
			(0, QString(os_->str().c_str()), kapp->makeStdCaption(i18n("???")));
#else
		KMessageBox::sorry
			(0, QString(os_->str()), kapp->makeStdCaption(i18n("???")));
#endif
		return;
	}
	out_.setf(ios::showpoint);
	staffCount_ = stafflist->count();
	badlist_.setAutoDelete(true);
	badlist_.clear();
	lastMeasureNum_ = 1;
	drum_problem_written_ = false;
	voiceStatList_ = new voice_stat_str[count_of_voices];
	countOfLyricsLines_ = new int[staffCount_];


	out_ << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << endl;
	out_ << "%                                  %" << endl;
	out_ << "%   ABC music output generated by  %" << endl;
	out_ << "%           \"noteedit\"             %" << endl;
	out_ << "%                                  %" << endl;
	out_ << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << endl << endl;
	out_ << "% PAGE LAYOUT" << endl;
	out_ << '%' << endl;
	dval =  expWin->ABCWidth->text().toDouble(&ok);
	if (!ok) dval = 17.0; else dval /= 10.0;
	out_ << "%%pagewidth\t" << dval << "cm" << endl;
	dval =  expWin->ABCHeight->text().toDouble(&ok);
	if (!ok) dval = 25.0; else dval /= 10.0;
	out_ << "%%pageheight\t" << dval << "cm" << endl;
	s = expWin->ABCscale->text();
	s.replace (reg, "");
	dval =  s.toDouble(&ok);
	if (!ok) dval = 0.75; else dval /= 100.0;
	out_ << "%%scale\t\t" << dval << endl;
	dval =  expWin->ABCStaffSep->text().toDouble(&ok);
	if (!ok) dval = 1.6; else dval /= 10.0;
	out_ << "%%staffsep\t" << dval << "cm" << endl;
	if (expWin->ABCExprAbove->isChecked()) {
		out_ << "%%exprabove\ttrue" << endl;
	}
	else {
		out_ << "%%exprabove\tfalse" << endl;
	}
	if (expWin->ABCMeasNumInBox->isChecked()) {
		out_ << "%%measurebox\ttrue" << endl;
	}
	else {
		out_ << "%%measurebox\tfalse" << endl;
	}
	out_ << '%' << endl;
	with_pedal_marks = false;
	for (staff_elem = stafflist->first(); staff_elem; staff_elem = stafflist->next()) {
		voice_count = staff_elem->voiceCount();
		voice_count = staff_elem->voiceCount();
		for (j = 0; j < voice_count; j++) {
			if (staff_elem->getVoiceNr(j)->voiceHasPedalMarks()) with_pedal_marks = true;
		}
	}
	if (with_pedal_marks) {
		outputPedalGlyphs();
	}


	out_ << "%%postscript /crdc{	% usage: str x y crdc - cresc, decresc, .." << endl;
	out_ << "%%postscript	/Times-Italic 14 selectfont" << endl;
	out_ << "%%postscript	M -6 4 RM show}!" << endl;
	out_ << "%%deco rit 6 crdc 20 2 24 ritard." << endl;
	out_ << "%%deco acc 6 crdc 20 2 24 accel." << endl << endl;


	out_ << "X: 1" << endl;
	if (!mainWidget->scTitle_.isEmpty()) {
		out_ << "T: " << mainWidget->scTitle_ << endl;
	}
	if (!mainWidget->scSubtitle_.isEmpty()) {
		out_ << "T: " << mainWidget->scSubtitle_ << endl;
	}
	if (!mainWidget->scAuthor_.isEmpty()) {
		out_ << "C: " << mainWidget->scAuthor_<< endl;
	}
	if (!mainWidget->scLastAuthor_.isEmpty()) {
		out_ << "C: " << mainWidget->scLastAuthor_ << endl;
	}
	if (!mainWidget->scCopyright_.isEmpty()) {
		out_ << "C: copyright: " << mainWidget->scCopyright_ << endl;
	}
	outputMeter(stafflist->first()->getVoiceNr(0)->getFirstTimeSig(), true);
	out_ << "L: 1/4 % default length" << endl;
	outputStaffAndVoiceDescription(stafflist, mainWidget);
	outputKeySig(stafflist->first()->getVoiceNr(0)->getFirstKeysig(), true);
	outputMidi(stafflist);
	firstClef = stafflist->first()->getVoiceNr(0)->getFirstClef();
	lastClef_ = new NClef(&(mainWidget->main_props_), &(stafflist->first()->staff_props_));
	k = 0;
	for (i = 0, staff_elem = stafflist->first(); staff_elem; staff_elem = stafflist->next(), i++) {
		voice_count = staff_elem->voiceCount();
		for (j = 0; j < voice_count; j++) {
			voice_elem = staff_elem->getVoiceNr(j);
			if (j == 0) {
				countOfLyricsLines_[i] = voice_elem->countOfLyricsLines();
			}
			voice_elem->prepareForWriting();
			if (k >= count_of_voices) {
				NResource::abort("NABCExport::exportStaffs");
			}
			voice_elem->setIdx(k++);
		}
		staff_elem->actualClef_.change(staff_elem->getVoiceNr(0)->getFirstClef());
	}
	do {
		something_written = false;
		out_ << "% " << lastMeasureNum_ << endl;
		for (i = 0, staff_elem = stafflist->first(); staff_elem; i++, staff_elem = stafflist->next()) {
			voice_count = staff_elem->voiceCount();
			voice_elem = staff_elem->getVoiceNr(0);
			lastClef_->change(&(staff_elem->actualClef_));
			if (writeFirstVoice(voice_elem, staff_elem->staffName_, i+1, staff_elem->voiceCount(), 4, i == staffCount_ - 1)) {
				something_written = true;
			}
			for (j = 0; j < countOfLyricsLines_[i]; j++) {
#if GCC_MAJ_VERS > 2
				if (lyricsLine_[j]->tellp() > 0) {
#else
				if (lyricsLine_[j]->pcount() > 0) {
					(*lyricsLine_[j]) << '\0';
#endif
					out_ << "w: " << lyricsLine_[j]->str() << endl;
				}
#ifdef BRACE_BALANCE /* for vi '%' usage */
				}
#endif
			}
			last_elem = voice_elem->getCurrentPosition();
			if (last_elem) {
				current_time = last_elem->midiTime_;
			}
			else {
				current_time = (1 << 30);
			}
			if (voice_count > 1) {
				staff_elem->mark();
			}
			for (j = 2; j <= voice_count; j++) {
				voice_elem = staff_elem->getVoiceNr(j-1);
				if (writeOtherVoicesTill(i+1, j, staff_elem->staffName_, voice_elem, staff_elem, current_time)) {
					something_written = true;
				}
			}
			if (voice_count > 1) {
				staff_elem->gotoMarkedPosition();
				staff_elem->actualClef_.change(lastClef_);
			}
		}
	}
	while (something_written);
	out_.close();
	delete []voiceStatList_;
	delete []countOfLyricsLines_;
	if (!badlist_.isEmpty()) {
		QString output;
		output = i18n
			("Noteedit has exported the score to ABC music but there are some\n"
			 "problems which will probably prevent successful PostScript output.\n");
		output += i18n("-----------------------------------------------------\n");
		for (bad = badlist_.first(); bad; bad = badlist_.next()) {
			switch (bad->type_) {
				case ABC_ERR_TUPLET:
				output += i18n
				( "Staff %1, measure %2: ABC music cannot deal with such kind of tuplets\n").arg(bad->staffnr_).arg(bad->barnr_);
					break;
				case ABC_ERR_IRREGULAER:
				output += i18n
				( "Staff %1 has irregular keysig. This cannot be expressed in ABC music\n").arg(bad->staffnr_);
					break;
				case ABC_ERR_DRUM_STAFF:
					output += i18n
						("Staff %1 contains drum staff. ABC music has only limited drum staff support\n")
						.arg(bad->staffnr_);
					break;
				case ABC_ERR_BRACE_NESTING:
					output += i18n
						("ABC music cannot deal with nested brackets/braces\n");
					break;
				case ABC_ERR_ONE_STAFF_BRACKET:
					output += i18n
						("ABC music cannot deal with a one-staff bracket\n");
					break;
				case ABC_ERR_VAS:
					output += i18n
						("Staff %1, measure %2: ABC music cannot deal with octaviation (va lines)\n").arg(bad->staffnr_).arg(bad->barnr_);
					break;
			}
		}
		NResource::exportWarning_->setOutput(i18n ("ABC music produced. But there are some problems."), &output);
		NResource::exportWarning_->show();
	}
}

bool NABCExport::writeFirstVoice(NVoice *voice_elem, QString staffName, int staff_nr, int voice_count, int measure_count, bool lastStaff) {
	NMusElement *elem, *elem2;
	NStaff *actual_staff;
	NChord *chord;
	NRest *rest;
	NNote *note;
	NClef *clef;
	NSign *sign;
	QString *lyrics;
	NChordDiagram *diag;
	badinfo *bad;
	bool inBeam = false;
	bool inTuplet = false;
	bool inGrace = false;
	int len;
	int idx;
	int i;

#if GCC_MAJ_VERS > 2
	for (i = 0; i < NUM_LYRICS; i++) {
		delete lyricsLine_[i];
		lyricsLine_[i] = new ostringstream();
	}
#else
	for (i = 0; i < NUM_LYRICS; i++) {
		lyricsLine_[i]->seekp(0);
	}
#endif
	elem = voice_elem->getCurrentPosition();
	if (!elem) return false;

	out_ << "[V: ";
	if (voice_count > 1) {
		out_ << createVoiceName(staffName, staff_nr, 1);
	}
	else {
		out_ << createVoiceName(staffName, staff_nr, 0);
	}
	out_ << "] ";

	actual_staff = voice_elem->getStaff();
	idx = voice_elem->getIdx();
	do {
		switch (elem->getType()) {
			case T_CHORD: writePendingSigns(idx);
				      voiceStatList_[idx].lastBarSym = 0;
				      chord = (NChord *) elem;
				      if (chord->status_ & STAT_TUPLET) {
				      	if (!inTuplet) {
						inTuplet = true;
						outputTupletStart(staff_nr, elem);
					}
				      }
				      if (inGrace && !(chord->status_ & STAT_GRACE)) {
				      	inGrace = false;
					out_ << '}';
				      }
				      if (chord->status_ & STAT_GRACE) {
				      	if (!inGrace) {
						inGrace = true;
						out_ << " {";
						if (chord->getSubType() == INTERNAL_MARKER_OF_STROKEN_GRACE) {
							out_ << '/';
						}
					}
				      }
				      if (!inTuplet && chord->getSubType() < QUARTER_LENGTH) {
				      	if (chord->status_ & STAT_BEAMED) {
						if (!inBeam) {
							if (!inGrace) out_ << ' ';
							inBeam = true;
						}
					}
				      }
				      else {
				         inBeam =false;
				      }
				      if (!inTuplet && !inBeam && !inGrace) {
				         out_ << ' ';
				      }
				      if (chord->lastBeamed()) {
				      	inBeam = false;
				      }
				      if (!inGrace && chord->getSlurPartner()) {
				      	out_ << '(';
					voiceStatList_[idx].slurDepth++;
				      }
				      for (i = 0; i < NUM_LYRICS; i++) {
				      	lyrics = chord->getLyrics(i);
				      	if (!lyrics && i < countOfLyricsLines_[staff_nr-1]) {
						(*lyricsLine_[i]) << " * ";
					}
					if (lyrics) {
						(*lyricsLine_[i]) << lyrics2ABC(lyrics) << ' ';
					}
				      }
				      if ((diag = chord->getChordChordDiagram()) != 0) {
					writeChordName(diag->getChordName());
				      }
				      if (chord->status_ & STAT_STACC)
						out_ << '.';
				      if (chord->status_ & STAT_SFORZ) 
					        out_ << "!sfz!";
				      if (chord->status_ & STAT_PORTA)
					        out_ << "!tenuto!";
				      if (chord->status_ & STAT_STPIZ)
					        out_ << "!wedge!";
				      if (chord->status_ & STAT_SFZND)
					        out_ << "!accent!";
				      if (chord->status2_ & STAT2_PEDAL_ON) {
				      		out_ << "!ped!";
				      }
				      if (chord->status2_ & STAT2_PEDAL_OFF) {
				      		out_ << "!ped-end!";
				      }
				      if (chord->status_ & STAT_FERMT) {
				      		if (chord->status_ & STAT_STEM_UP) {
							out_ << "!fermata!";
						}
						else {
							out_ << "!invertedfermata!";
						}
				      }
				      if (chord->va_) {
				      	bad = new badinfo(ABC_ERR_VAS, staff_nr, lastMeasureNum_); badlist_.append(bad);
				      }
				      if (!inGrace && voiceStatList_[idx].trillendpos != 0 && chord->getBbox()->right() > voiceStatList_[idx].trillendpos) {
					voiceStatList_[idx].trillendpos = 0;
					out_ <<  "!trill)!";
				      }
				      if (chord->trill_ != 0) {
					if (chord->trill_ > 0) {
						out_ << "!trill!";
					}
					if (voice_elem->findNoteCountTillTrillEnd(chord)) {
						voiceStatList_[idx].trillendpos = chord->getTrillEnd();
						out_ << "!trill(!";
					}
				      }
				      if (!inGrace && voiceStatList_[idx].lastDynSym && chord->getBbox()->right() > voiceStatList_[idx].dynEndPos) {
				      	out_ << voiceStatList_[idx].lastDynSym;
					voiceStatList_[idx].lastDynSym = 0;
					voiceStatList_[idx].dynEndPos = 0;
				      }
				      if (chord->dynamic_) {
				      	out_ << (chord->dynamicAlign_ ? "!crescendo(!" : "!diminuendo(!");
					voiceStatList_[idx].dynEndPos = chord->getDynamicEnd();
					voiceStatList_[idx].lastDynSym = (char *) (chord->dynamicAlign_ ? "!crescendo)!" : "!diminuendo)!");
				      }
				      if (elem->status_ & STAT_ARPEGG) {
				      	out_ << "!arpeggio!";
				      }
				      if (chord->getNoteList()->count() > 1) {
				      	out_ << '[';
				      }
				      for (note = chord->getNoteList()->first(); note; note = chord->getNoteList()->next()) {
				     	outputNote(note, &(actual_staff->actualClef_), staff_nr);
					if (!((chord->status_ & STAT_GRACE) && chord->getSubType() == INTERNAL_MARKER_OF_STROKEN_GRACE)) {
						outputLength(chord->getSubType(), chord->status_);
					}
					if (note->status & STAT_TIED) out_ << '-';
				      }
				      if (chord->getNoteList()->count() > 1) {
				      	out_ << ']';
				      }
				      if (voiceStatList_[idx].slurDepth > 0 && chord->getSlurStart()) {
				      	out_ << ')';
					voiceStatList_[idx].slurDepth--;
				      }
				      if (chord->status_ & STAT_LAST_TUPLET) {
				        inTuplet = false;
					out_ << ' ';
				      }
				      break;
			case T_REST: writePendingSigns(idx);
				     voiceStatList_[idx].lastBarSym = 0;
				     rest = (NRest *) elem;
				     if (rest->status_ & STAT_TUPLET) {
				     	if (!inTuplet) {
						inTuplet = true;
						outputTupletStart(staff_nr, elem);
					}
				     }
				     inBeam =false;
				     if (inGrace) {
				     	inGrace = false;
					out_ << '}';
				     }
				     if (!inTuplet) out_ << ' ';

				     if (rest->getSubType() == MULTIREST) {
				     	out_ << 'Z';
					len = rest->getMultiRestLength() * QUARTER_LENGTH;
				     }
				     else if (rest->status_ & STAT_HIDDEN) {
				        out_ << 'x';
					len = rest->getSubType();
				     }
				     else {
				        out_ << 'z';
					len = rest->getSubType();
				     }
				     outputLength(len, rest->status_);
				     if (rest->status_ & STAT_LAST_TUPLET) {
				        inTuplet = false;
					out_ << ' ';
				     }
				     break;
			case T_SIGN: inBeam =false;
				     if (inGrace) {
				     	inGrace = false;
					out_ << '}';
				     }
				     sign = (NSign *) elem;
				     if (sign->getSubType() & BAR_SYMS) {
				     	if (lastStaff) lastMeasureNum_ = sign->getBarNr();
					measure_count--;
					elem2 = voice_elem->getNextPosition();
					if (!elem2) {
						outputBarSym(sign, 0, voice_elem->isLast());
						break;
					}
					if (elem2->getType() == T_SIGN) {
						switch (elem2->getSubType()) {
							case SPECIAL_ENDING1: 
								outputBarSym(sign, 1, voice_elem->isLast()); break;
							case SPECIAL_ENDING2: 
								outputBarSym(sign, 2, voice_elem->isLast()); break;
							default: voice_elem->getPrevPosition(); 
								outputBarSym(sign, 0, voice_elem->isLast()); break;
						}
					}
					else {
						voice_elem->getPrevPosition();
						outputBarSym(sign, 0, voice_elem->isLast());
					}
					break;
				     }
				     voiceStatList_[idx].lastBarSym = 0;
				     switch (sign->getSubType()) {
				     	case VOLUME_SIG: voiceStatList_[idx].pendingVolumes = sign; break;
					case SEGNO:
					case CODA: voiceStatList_[idx].pendingSegnos = sign; break;
					case DAL_SEGNO:
					case DAL_SEGNO_AL_FINE:
					case DAL_SEGNO_AL_CODA:
					case FINE: voiceStatList_[idx].pendingSegnos2 = sign; break;
					case RITARDANDO:
					case ACCELERANDO: voiceStatList_[idx].pendingRitAccel = sign; break;
					case TEMPO_SIGNATURE: out_ << "[Q:1/4=" << sign->getTempo() << ']'; break;
				     }
				     break;
			case T_CLEF: inBeam =false;
				     voiceStatList_[idx].lastBarSym = 0;
				     if (inGrace) {
				     	inGrace = false;
					out_ << '}';
				     }
				     clef = (NClef *) elem;
				     actual_staff->actualClef_.change(clef);
				     if (lastMeasureNum_ < 2) break;
				     out_ << "[V: ";
				     if (voice_count > 1) {
					out_ << createVoiceName(staffName, staff_nr, 1) << ' ';
				     }
				     else {
					out_ << createVoiceName(staffName, staff_nr, 0) << ' ';
				     }
				     outputClefInfo(clef);
				     out_ << "] ";
				     break;
			case T_TIMESIG: 
				     voiceStatList_[idx].lastBarSym = 0;
				     inBeam =false;
				     if (inGrace) {
				     	inGrace = false;
					out_ << '}';
				     }
				     if (lastMeasureNum_ < 2) break;
				     out_ << '[';
				     outputMeter((NTimeSig *) elem, false);
				     out_ << ']';
				     break;
			case T_KEYSIG:
				     voiceStatList_[idx].lastBarSym = 0;
				     inBeam =false;
				     if (inGrace) {
				     	inGrace = false;
					out_ << '}';
				     }
				     if (lastMeasureNum_ < 2) break;
				     out_ << '[';
				     outputKeySig((NKeySig *) elem, false);
				     out_ << ']';
				     break;
			default:     inBeam =false;
				     voiceStatList_[idx].lastBarSym = 0;
				     if (inGrace) {
				     	inGrace = false;
					out_ << '}';
				     }
		}
		elem = voice_elem->getNextPosition();
	}
	while (elem && measure_count > 0);
	out_ << endl;
	return true;
}

bool NABCExport::writeOtherVoicesTill(int staff_nr, int voice_nr, QString staffName, NVoice *voice_elem, NStaff *staff_elem, int stopTime) {
	NMusElement *elem;
	NStaff *actual_staff;
	NChord *chord;
	NRest *rest;
	NNote *note;
	bool inBeam = false;
	bool inTuplet = false;
	bool inGrace = false;
	int len;
	int idx;

	actual_staff = voice_elem->getStaff();
	elem = voice_elem->getCurrentPosition();


	if (!elem || elem->midiTime_ >= stopTime) return false;
	actual_staff->resetSpecialElement();
	actual_staff->syncSpecialElement(elem->getXpos());
	idx = voice_elem->getIdx();

	out_ << "[V: " << createVoiceName(staffName, staff_nr, voice_nr) << "] ";

	while (elem && elem->midiTime_ < stopTime) {
		handleSpecialElements(actual_staff, elem);
		switch (elem->getType()) {
			case T_CHORD: chord = (NChord *) elem;
				      if (chord->status_ & STAT_TUPLET) {
				      	if (!inTuplet) {
						inTuplet = true;
						outputTupletStart(staff_nr, elem);
					}
				      }
				      if (inGrace && !(chord->status_ & STAT_GRACE)) {
				      	inGrace = false;
					out_ << '}';
				      }
				      if (chord->status_ & STAT_GRACE) {
				      	if (!inGrace) {
						inGrace = true;
						out_ << '{';
						if (chord->getSubType() == INTERNAL_MARKER_OF_STROKEN_GRACE) {
							out_ << '/';
						}
					}
				      }
				      if (!inTuplet && chord->getSubType() < QUARTER_LENGTH) {
				      	if (chord->status_ & STAT_BEAMED) {
						if (!inBeam) {
							if (!inGrace) out_ << ' ';
							inBeam = true;
						}
					}
				      }
				      else {
				         inBeam =false;
				      }
				      if (!inTuplet && !inBeam && !inGrace) {
				         out_ << ' ';
				      }
				      if (chord->lastBeamed()) {
				      	inBeam = false;
				      }
				      if (!inGrace && chord->getSlurPartner()) {
				      	out_ << '(';
					voiceStatList_[idx].slurDepth++;
				      }
				      if (chord->status_ & STAT_STACC)
						out_ << '.';
				      if (chord->status_ & STAT_SFORZ) 
					        out_ << "!sfz!";
				      if (chord->status_ & STAT_PORTA)
					        out_ << "!tenuto!";
				      if (chord->status_ & STAT_STPIZ)
					        out_ << "!wedge!";
				      if (chord->status_ & STAT_SFZND)
					        out_ << "!accent!";
				      if (chord->status_ & STAT_FERMT) {
				      		if (chord->status_ & STAT_STEM_UP) {
							out_ << "!fermata!";
						}
						else {
							out_ << "!invertedfermata!";
						}
				      }
				      if (elem->status_ & STAT_ARPEGG) {
				      	out_ << "!arpeggio!";
				      }
				      if (chord->getNoteList()->count() > 1) {
				      	out_ << '[';
				      }

				      staff_elem->setCorrectClefAccordingTime(elem->midiTime_);
				      for (note = chord->getNoteList()->first(); note; note = chord->getNoteList()->next()) {
				     	outputNote(note, &(actual_staff->actualClef_), staff_nr);
					if (!((chord->status_ & STAT_GRACE) && chord->getSubType() == INTERNAL_MARKER_OF_STROKEN_GRACE)) {
						outputLength(chord->getSubType(), chord->status_);
					}
					if (note->status & STAT_TIED) out_ << '-';
				      }
				      if (chord->getNoteList()->count() > 1) {
				      	out_ << ']';
				      }
				      if (voiceStatList_[idx].slurDepth > 0 && chord->getSlurStart()) {
				      	out_ << ')';
					voiceStatList_[idx].slurDepth--;
				      }
				      if (chord->status_ & STAT_LAST_TUPLET) {
				        inTuplet = false;
					out_ << ' ';
				      }
				      break;
			case T_REST: rest = (NRest *) elem;
				     if (rest->status_ & STAT_TUPLET) {
				     	if (!inTuplet) {
						inTuplet = true;
						outputTupletStart(staff_nr, elem);
					}
				     }
				     inBeam =false;
				     if (inGrace) {
				     	inGrace = false;
					out_ << '}';
				     }
				     if (!inTuplet) out_ << ' ';

				     if (rest->getSubType() == MULTIREST) {
				     	out_ << 'Z';
					len = rest->getMultiRestLength() * QUARTER_LENGTH;
				     }
				     else if (rest->status_ & STAT_HIDDEN) {
				        out_ << 'x';
					len = rest->getSubType();
				     }
				     else {
				        out_ << 'z';
					len = rest->getSubType();
				     }
				     outputLength(len, rest->status_);
				     if (rest->status_ & STAT_LAST_TUPLET) {
				        inTuplet = false;
					out_ << ' ';
				     }
				     break;
			default:     inBeam =false;
				     if (inGrace) {
				     	inGrace = false;
					out_ << '}';
				     }
		}
		elem = voice_elem->getNextPosition();
	}
	handleSpecialElements(actual_staff, elem);
	out_ << endl;
	return true;
}

void NABCExport::handleSpecialElements(NStaff *staff_elem, NMusElement *elem) {
	NMusElement *specElem;
	int xpos, volta;
	bool ok;

	if (elem) {
		xpos = elem->getXpos();
	}
	else {
		xpos = (1 << 30);
	}
	while (specElem = staff_elem->checkSpecialElement(xpos, &volta)) {
		switch (specElem->getType()) {
			case T_SIGN: ok = false;
				     switch (specElem->getSubType()) {
				        case END_BAR: ok = true;  out_ << " |"; break;
					case SIMPLE_BAR: ok = true;  out_ << " |"; break;
			             	case REPEAT_OPEN:ok = true;   out_ << " |:"; break;
					case REPEAT_CLOSE: ok = true;  out_ << " :|"; break; 
					case REPEAT_OPEN_CLOSE:ok = true;  out_ << " :||:"; break; 
					case DOUBLE_BAR: ok = true;  out_ << " ||";  break;
				     }
				     if (ok && volta) {
					out_ << volta << ' ';
				     }
				     break;
			case T_CLEF: staff_elem->actualClef_.change((NClef *) specElem);
				     break;
		}
	}
}

void NABCExport::writeChordName(QString chordname) {
	out_ << '"' << chordname << '"' << ' ';
}
				    
void NABCExport::outputBarSym(NSign *sign, int volta, bool isLast) {
	switch (sign->getSubType()) {
		case END_BAR: out_ << " |]"; break;
		case SIMPLE_BAR: if (isLast) out_ << " |]"; else out_ << " |"; break;
		case REPEAT_OPEN:  out_ << " |:"; break;
		case REPEAT_CLOSE:  out_ << " :|"; break; 
		case REPEAT_OPEN_CLOSE: out_ << " :||:"; break; 
		case DOUBLE_BAR:  out_ << " ||";  break;
		default: NResource::abort("NABCExport::outputBarSym");
	}
	if (volta) {
		out_ << volta << ' ';
	}
}

void NABCExport::writePendingSigns(int idx) {
	NSign *sign;

	if (sign = voiceStatList_[idx].pendingVolumes) {
		voiceStatList_[idx].pendingVolumes = 0;
		switch (sign->getVolType()) {
			case V_PPPIANO : out_ << "!ppp!"; break;
			case V_PPIANO  : out_ << "!pp!"; break;
			case V_PIANO   : out_ << "!p!"; break;
			case V_FORTE   : out_ << "!f!"; break;
			case V_FFORTE  : out_ << "!ff!"; break;
			case V_FFFORTE : out_ << "!fff!"; break;
			default        : out_ << "!mf!"; break;
		}
	}
	if (sign = voiceStatList_[idx].pendingSegnos) {
		voiceStatList_[idx].pendingSegnos = 0;
		switch(sign->getSubType()) {
			case SEGNO     : out_ << "!segno! "; break;
			case CODA      : out_ << "!coda! "; break;
		}
	}
	if (sign = voiceStatList_[idx].pendingSegnos2) {
		voiceStatList_[idx].pendingSegnos2 = 0;
		switch(sign->getSubType()) {
			case DAL_SEGNO : out_ << "!D.S.! "; break;
			case FINE      : out_ << "!fine!"  << endl; break;
			case DAL_SEGNO_AL_FINE: out_ << "\"D.S. al fine\" "; break;
			case DAL_SEGNO_AL_CODA: out_ << "\"D.S. al coda\" "; break;
		}
	}
	if (sign = voiceStatList_[idx].pendingRitAccel) {
		voiceStatList_[idx].pendingRitAccel = 0;
		switch(sign->getSubType()) {
			case ACCELERANDO: out_ << "!acc! "; break;
			case RITARDANDO: out_ << "!rit! "; break;
		}
	}
	voiceStatList_[idx].pendingRitAccel = 0;
}
	


void NABCExport::outputNote(NNote *note, NClef *actualClef, int staff_nr) {
	int octave;
	char notename;
	bool percussion = actualClef->getSubType() == DRUM_CLEF || actualClef->getSubType() == DRUM_BASS_CLEF;
	badinfo *bad;
	if ((note->status & BODY_MASK) && !drum_problem_written_)  {
		drum_problem_written_ = true;
		bad = new badinfo(ABC_ERR_DRUM_STAFF, staff_nr, lastMeasureNum_);
		badlist_.append(bad);
	}
	if (percussion) {
		out_ << "^";
	}
	else if (note->needed_acc || (note->status & STAT_FORCE)) {
		switch(note->offs) {
			case -2: out_ << "__"; break;
			case -1: out_ << "_";  break;
			case  0: out_ << "=";  break;
			case  1: out_ << "^";  break;
			case  2: out_ << "^^";  break;
		}
	}
	if (percussion) {
		notename = NResource::nullClef_->line2Name(note->line, &octave, false, true);
	}
	else {
		notename = actualClef->line2Name(note->line, &octave, false, true);
		if (actualClef->getSubType() == BASS_CLEF || actualClef->getSubType() == DRUM_BASS_CLEF) {
			octave--;
		}
	}
	if (octave < 1) {
		octave++;
		out_ << (char) toupper(notename);
	}
	else {
		out_ << notename;
	}
	for (; octave > 1; octave--) out_ << '\'';
	for (; octave < 1; octave++) out_ << ',';
}

void NABCExport::outputLength(int len, unsigned int status) {
	unsigned int k;
	if (len == QUARTER_LENGTH && !(status & (STAT_SINGLE_DOT | STAT_DOUBLE_DOT))) return;
	if (status & STAT_GRACE) len <<= 1; // Dont' know ???
	if (len > DOUBLE_WHOLE_LENGTH) {
		out_ << (len / QUARTER_LENGTH);
		return;
	}
	switch (len) {
		case DOUBLE_WHOLE_LENGTH: 
			switch (status & DOT_MASK) {
				case STAT_DOUBLE_DOT: out_ << "13"; break;
				case STAT_SINGLE_DOT: out_ << "12"; break;
				default: out_ << "8"; break;
			}
			break;
		case WHOLE_LENGTH:
			switch (status & DOT_MASK) {
				case STAT_DOUBLE_DOT: out_ << "7"; break;
				case STAT_SINGLE_DOT: out_ << "6"; break;
				default: out_ << "4"; break;
			}
			break;
		case HALF_LENGTH:
			switch (status & DOT_MASK) {
				case STAT_DOUBLE_DOT: out_ << "14/4"; break;
				case STAT_SINGLE_DOT: out_ << "3"; break;
				default: out_ << "2"; break;
			}
			break;
		default:
			switch (status & DOT_MASK) {
				case STAT_DOUBLE_DOT: out_ << "7/" << ((QUARTER_LENGTH / len) * 4); break;
				case STAT_SINGLE_DOT: out_ << "3/" << ((QUARTER_LENGTH / len) * 2); break;
				default: //out_ << '/' << (QUARTER_LENGTH / len); break;
					 for(k = (QUARTER_LENGTH / len) - 1; k; k >>= 1) {
					 	out_ << '/';
					 }
					 break;
					 
			}
	}
}

void NABCExport::outputTupletStart (int staff_nr, NMusElement *elem) {
	badinfo *bad;
	int real_note_count;
	bool play_time_written = false;

#define TUP_TEST(nr)  if (elem->getPlaytime() != nr) {QString s; s.sprintf(":%d", elem->getPlaytime()); out_ << s; play_time_written = true;}
	out_ << '(';
	switch (elem->getNumNotes()) {
		case 2: out_ << '2'; TUP_TEST(3); break;
		case 3: out_ << '3'; TUP_TEST(2); break;
		case 4: out_ << '4'; TUP_TEST(3); break;
		case 5: out_ << '5';
			out_ << ':' << elem->getPlaytime(); play_time_written = true;
			break;
		case 6: out_ << '6'; TUP_TEST(2); break;
		case 7: out_ << ':' << elem->getPlaytime(); play_time_written = true;
			out_ <<  '7';
			break;
		case 8: out_ << '8'; TUP_TEST(3); break;
		case 9:	out_ << '9';
			out_ << ':' << elem->getPlaytime(); play_time_written = true;
			break;
		default: bad = new badinfo(ABC_ERR_TUPLET, staff_nr, lastMeasureNum_); badlist_.append(bad);
			break;
	}
	real_note_count = elem->getTupletList()->count();
	if (elem->getNumNotes() != real_note_count) {
		QString s;
		if (!play_time_written) out_ << ':';
		s.sprintf(":%d", real_note_count);
		out_ << s;
	}
}
			

void NABCExport::outputStaffAndVoiceDescription(QList<NStaff> *stafflist, NMainFrameWidget *mainWidget) {
	NStaff *staff_elem;
	NVoice *voice_elem;
	int voice_count;
	int staffcount;
	bool contbar;
	bool nesting_reported = false;
	bool onestaffproblem_reported = false;
	badinfo *bad;
	int nesting = 0;
	int i, j, k;

	staffcount = stafflist->count();
	out_ << "%%staves ";
	for (i = 0, staff_elem = stafflist->first(); staff_elem; i++, staff_elem = stafflist->next()) {
		for (k = 0; k < staffcount; k++) {
			if (mainWidget->bracketMatrix_[k].valid) {
				if (mainWidget->bracketMatrix_[k].beg == i) {
					out_ << " [ ";
					nesting++;
					if (nesting > 1 && !nesting_reported) {
						bad = new badinfo(ABC_ERR_BRACE_NESTING, 1 /* dummy */, 1 /* dummy */);
						badlist_.append(bad);
						nesting_reported = true;
					}
					if (mainWidget->bracketMatrix_[k].beg == mainWidget->bracketMatrix_[k].end &&
						!onestaffproblem_reported) {
						bad = new badinfo(ABC_ERR_ONE_STAFF_BRACKET, 1 /* dummy */, 1 /* dummy */);
						badlist_.append(bad);
						onestaffproblem_reported = true;
					}
				}
			}
		}
		for (k = 0; k < staffcount; k++) {
			if (mainWidget->braceMatrix_[k].valid) {
				if (mainWidget->braceMatrix_[k].beg == i) {
					out_ << " { ";
					nesting++;
					if (nesting > 1 && !nesting_reported) {
						bad = new badinfo(ABC_ERR_BRACE_NESTING, 1 /* dummy */, 1 /* dummy */);
						badlist_.append(bad);
						nesting_reported = true;
					}
				}
			}
		}
		voice_count = staff_elem->voiceCount();
		if (voice_count > 1) {
			out_ << '(';
			for (j = 0, voice_elem = staff_elem->voicelist_.first(); voice_elem; j++, voice_elem = staff_elem->voicelist_.next()) {
				out_ << createVoiceName(staff_elem->staffName_, i+1, j+1);
				if (j < voice_count - 1) {
					out_ << ' ';
				}
			}
			out_ << ')';
		}
		else {
			out_ << createVoiceName(staff_elem->staffName_, i+1, 0);
		}
		out_ << ' ';
		contbar = false;
		for (k = 0; k < staffcount; k++) {
			if (mainWidget->barCont_[k].valid && i >= mainWidget->barCont_[k].beg && i < mainWidget->barCont_[k].end) {
				contbar = true;
			}
		}
		if (!contbar && i < staffcount - 1) {
			out_ << "| ";
		}
		for (k = 0; k < staffcount; k++) {
			if (mainWidget->braceMatrix_[k].valid) {
				if (mainWidget->braceMatrix_[k].end == i) {
					out_ << "} ";
					nesting--;
				}
			}
		}
		for (k = 0; k < staffcount; k++) {
			if (mainWidget->bracketMatrix_[k].valid) {
				if (mainWidget->bracketMatrix_[k].end == i) {
					out_ << "] ";
					nesting--;
				}
			}
		}
	}
	out_ << endl;
	for (i = 0, staff_elem = stafflist->first(); staff_elem; i++, staff_elem = stafflist->next()) {
		if (staff_elem->voiceCount() > 1) {
			for (j = 0, voice_elem = staff_elem->voicelist_.first(); voice_elem; j++, voice_elem = staff_elem->voicelist_.next()) {
				out_ << "V: " << createVoiceName(staff_elem->staffName_, i+1, j+1) << ' ';
				if (j == 0) outputVoiceParams(voice_elem, staff_elem->staffName_);
				out_ << endl;
			}
		}
		else {
			out_ << "V: " << createVoiceName(staff_elem->staffName_, i+1, 0) << ' ';
			outputVoiceParams(staff_elem->getVoiceNr(0), staff_elem->staffName_);
			out_ << endl;
		}
	}
}

void NABCExport::outputVoiceParams(NVoice *voice, QString staffName) {
	NClef *clef;
	int ok;

	clef = voice->getFirstClef();
	ok  = outputClefInfo(clef);
	if (ok) {
		switch (clef->getShift()) {
			case  12: out_ << "+8"; break;
			case -12: out_ << "-8"; break;
		}
	}
	out_ << ' ';

	if (!staffName.isEmpty()) {
		out_ << "name=\"" << staffName << '"';
	}
}

bool NABCExport::outputClefInfo(NClef *clef) {
	bool ok = true;
	switch (clef->getSubType()) {
		case TREBLE_CLEF: out_ << "clef=treble"; break;
		case BASS_CLEF: out_ << "clef=bass"; break;
		case ALTO_CLEF: out_ << "clef=alto"; break;
		case TENOR_CLEF: out_ << "clef=alto4"; break;
		case DRUM_CLEF: out_ << "clef=perc"; break;
		case DRUM_BASS_CLEF: out_ << "clef=perc"; break;
		default: NResource::abort("NABCExport::outputClefInfo");
	}
	return ok;
}

QString NABCExport::createVoiceName(QString staffName,  int staff_nr, int voice_nr) {
	QString s, t;
	QRegExp reg = QRegExp("[ \\.]");

	if (staffName.isEmpty()) {
		s = 'S';
	}
	else {
		s = staffName;
	}
	t.sprintf("%d", staff_nr);
	s += t;
	if (voice_nr) {
		t.sprintf("V%d", voice_nr);
		s += t;
	}
	s.replace (reg, "_");
	return s;
}


void NABCExport::outputMeter(NTimeSig *timesig, bool inHeader) {
	if (timesig) {
		out_ << "M: " << timesig->getNumerator() << '/' << timesig->getDenominator();
		if (inHeader) {
			out_ << " % time signature" << endl;
		}
	}
}

void NABCExport::outputKeySig(NKeySig *key, bool inHeader) {
	int kind, count;
	badinfo *bad;
	out_ << "K: ";

	if (key->isRegular(&kind, &count)) {
		switch(kind) {
			case STAT_CROSS:
				switch (count) {
					case 0: out_ << 'C'; break;
					case 1: out_ << 'G'; break;
					case 2: out_ << 'D'; break;
					case 3: out_ << 'A'; break;
					case 4: out_ << 'E'; break;
					case 5: out_ << 'B'; break;
					case 6: out_ << "F#"; break;
					case 7: out_ << "C#"; break;
					default: NResource::abort("NABCExport::outputKeySig", 1);
				}
				break;
			case STAT_FLAT:
				switch (count) {
					case 0: out_ << 'C'; break;
					case 1: out_ << 'F'; break;
					case 2: out_ << "Bb"; break;
					case 3: out_ << "Eb"; break;
					case 4: out_ << "Ab"; break;
					case 5: out_ << "Db"; break;
					case 6: out_ << "Gb"; break;
					case 7: out_ << "Cb"; break;
					default: NResource::abort("NABCExport::outputKeySig", 2);
				}
				break;
			case STAT_NO_ACC:
				out_ << "C";
				break;
			default: NResource::abort("NABCExport::outputKeySig", 3);
		}
	}
	else {
		bad = new badinfo(ABC_ERR_IRREGULAER, 1, 0);
		badlist_.append(bad);
		out_ << "C";
	}
	if (inHeader) out_ << " % key signature" << endl;
}

void NABCExport::outputMidi(QList<NStaff> *stafflist) {
	NStaff *staff_elem;
	NVoice *voice_elem;
	int voice_count;
	int i, j, k = 1;
	extern char *instrTab[];
	out_ << '%' << endl;

	for (i = 0, staff_elem = stafflist->first(); staff_elem; i++, staff_elem = stafflist->next()) {
		voice_count = staff_elem->voiceCount();
		for (j = 0; j < voice_count; j++) {
			voice_elem = staff_elem->getVoiceNr(j);
			out_ << "%%MIDI program " << k++ << ' ' << staff_elem->getVoice() << " % ";
			out_ << i18n( instrTab[staff_elem->getVoice()] ) << endl;
		}
	}
	out_ << '%' << endl;
}

	
QString NABCExport::lyrics2ABC(QString *lyrics) {
	QString ret;
	QRegExp reg;

	
	ret = QString(*lyrics);

	reg = QRegExp("^<.[^>]*>$");
	if (ret.find(reg) != -1) {
		reg = QRegExp("^<");
		ret.replace (reg, "");
		reg = QRegExp(">$");
		ret.replace (reg, "");
		reg = QRegExp(" ");
		ret.replace (reg, "~");
	}
	reg = QRegExp("^ *[-\\*] *$");
	if (ret.find(reg) != -1) {
		ret = '*';
		return ret;
	}
	reg = QRegExp("ä");
	ret.replace (reg, "\\\"a");
	reg = QRegExp("ö");
	ret.replace (reg, "\\\"o");
	reg = QRegExp("ü");
	ret.replace (reg, "\\\"u");
	reg = QRegExp("Ä");
	ret.replace (reg, "\\\"A");
	reg = QRegExp("Ö");
	ret.replace (reg, "\\\"O");
	reg = QRegExp("Ü");
	ret.replace (reg, "\\\"U");
	reg = QRegExp("ß");
	ret.replace (reg, "\\ss");
	reg = QRegExp("_");
	ret.replace (reg, "\\_");
	return ret;
}

void NABCExport::outputPedalGlyphs() {
	out_ << "%" << endl;
	out_ << "% -- pedal glyph" << endl;
	out_ << "% (from CMN http://ccrma-www.stanford.edu/software/cmn/cmn/cmn.html)" << endl;
	out_ << "%%postscript /ped {	% usage: str x y ped" << endl;
	out_ << "%%postscript	gsave 4 add exch -10 add exch T 26 dup scale" << endl;
	out_ << "%%postscript	0.368 0.074 moveto" << endl;
	out_ << "%%postscript	0.341 0.121 0.335 0.147 0.371 0.203 curveto" << endl;
	out_ << "%%postscript	0.435 0.289 0.531 0.243 0.488 0.155 curveto" << endl;
	out_ << "%%postscript	0.472 0.117 0.434 0.096 0.414 0.080 curveto" << endl;
	out_ << "%%postscript	0.429 0.038 0.494 -0.006 0.541 0.075 curveto" << endl;
	out_ << "%%postscript	0.559 0.123 0.558 0.224 0.663 0.252 curveto" << endl;
	out_ << "%%postscript	0.603 0.354 0.449 0.393 0.461 0.405 curveto" << endl;
	out_ << "%%postscript	0.902 0.262 0.705 -0.124 0.555 0.046 curveto" << endl;
	out_ << "%%postscript	0.488 -0.032 0.417 0.021 0.389 0.055 curveto" << endl;
	out_ << "%%postscript	0.303 -0.018 0.303 -0.020 0.248 0.040 curveto" << endl;
	out_ << "%%postscript	0.218 0.108 0.191 0.062 0.164 0.047 curveto" << endl;
	out_ << "%%postscript	0.010 -0.056 0.032 0.019 0.124 0.062 curveto" << endl;
	out_ << "%%postscript	0.229 0.117 0.200 0.091 0.228 0.195 curveto" << endl;
	out_ << "%%postscript	0.240 0.241 0.149 0.250 0.166 0.311 curveto" << endl;
	out_ << "%%postscript	0.207 0.493 lineto" << endl;
	out_ << "%%postscript	-0.041 0.441 0.049 0.261 0.126 0.387 curveto" << endl;
	out_ << "%%postscript	0.138 0.381 lineto" << endl;
	out_ << "%%postscript	-0.020 0.119 -0.100 0.472 0.220 0.507 curveto" << endl;
	out_ << "%%postscript	0.548 0.486 0.399 0.171 0.254 0.374 curveto" << endl;
	out_ << "%%postscript	0.264 0.384 lineto" << endl;
	out_ << "%%postscript	0.338 0.259 0.521 0.449 0.228 0.488 curveto" << endl;
	out_ << "%%postscript	0.198 0.356 lineto" << endl;
	out_ << "%%postscript	0.181 0.304 0.273 0.294 0.262 0.241 curveto" << endl;
	out_ << "%%postscript	0.229 0.101 lineto" << endl;
	out_ << "%%postscript	0.273 0.070 0.282 -0.038 0.368 0.074 curveto" << endl;
	out_ << "%%postscript	0.391 0.094 moveto" << endl;
	out_ << "%%postscript	0.456 0.130 0.476 0.171 0.468 0.213 curveto" << endl;
	out_ << "%%postscript	0.452 0.276 0.333 0.171 0.391 0.094 curveto" << endl;
	out_ << "%%postscript	0.627 0.019 moveto" << endl;
	out_ << "%%postscript	0.533 0.041 0.586 0.228 0.678 0.229 curveto" << endl;
	out_ << "%%postscript	0.729 0.170 0.712 0.025 0.627 0.019 curveto" << endl;
	out_ << "%%postscript	eofill" << endl;
	out_ << "%%postscript	0.8 0.04 0.04 0 360 newpath arc fill" << endl;
	out_ << "%%postscript	pop grestore}!" << endl;
	out_ << "%" << endl;
	out_ << "% -- pedal off glyph" << endl;
	out_ << "% (from CMN http://ccrma-www.stanford.edu/software/cmn/cmn/cmn.html)" << endl;
	out_ << "%%postscript /pedoff {	% usage: str x y ped" << endl;
	out_ << "%%postscript	gsave 4 add exch -5 add exch T 26 dup scale" << endl;
	out_ << "%%postscript	0.219 0.198 moveto" << endl;
	out_ << "%%postscript	0.231 0.172 0.195 0.138 0.162 0.173 curveto" << endl;
	out_ << "%%postscript	0.149 0.219 0.206 0.231 0.219 0.198 curveto" << endl;
	out_ << "%%postscript	0.144 0.242 moveto" << endl;
	out_ << "%%postscript	0.166 0.223 0.193 0.230 0.181 0.267 curveto" << endl;
	out_ << "%%postscript	0.178 0.306 0.144 0.302 0.151 0.335 curveto" << endl;
	out_ << "%%postscript	0.160 0.381 0.225 0.377 0.224 0.330 curveto" << endl;
	out_ << "%%postscript	0.228 0.302 0.198 0.306 0.197 0.267 curveto" << endl;
	out_ << "%%postscript	0.194 0.237 0.213 0.222 0.237 0.247 curveto" << endl;
	out_ << "%%postscript	0.263 0.276 0.234 0.297 0.268 0.322 curveto" << endl;
	out_ << "%%postscript	0.314 0.347 0.354 0.297 0.316 0.259 curveto" << endl;
	out_ << "%%postscript	0.296 0.237 0.273 0.266 0.246 0.237 curveto" << endl;
	out_ << "%%postscript	0.223 0.217 0.232 0.194 0.266 0.197 curveto" << endl;
	out_ << "%%postscript	0.303 0.202 0.302 0.232 0.332 0.228 curveto" << endl;
	out_ << "%%postscript	0.381 0.232 0.388 0.156 0.332 0.152 curveto" << endl;
	out_ << "%%postscript	0.302 0.148 0.302 0.185 0.266 0.183 curveto" << endl;
	out_ << "%%postscript	0.231 0.186 0.228 0.169 0.245 0.143 curveto" << endl;
	out_ << "%%postscript	0.273 0.116 0.297 0.141 0.316 0.117 curveto" << endl;
	out_ << "%%postscript	0.350 0.075 0.303 0.029 0.258 0.062 curveto" << endl;
	out_ << "%%postscript	0.237 0.082 0.261 0.102 0.233 0.133 curveto" << endl;
	out_ << "%%postscript	0.212 0.151 0.194 0.147 0.197 0.113 curveto" << endl;
	out_ << "%%postscript	0.203 0.075 0.232 0.075 0.230 0.043 curveto" << endl;
	out_ << "%%postscript	0.223 -0.004 0.159 -0.002 0.152 0.042 curveto" << endl;
	out_ << "%%postscript	0.148 0.075 0.185 0.076 0.183 0.113 curveto" << endl;
	out_ << "%%postscript	0.183 0.147 0.163 0.150 0.141 0.133 curveto" << endl;
	out_ << "%%postscript	0.113 0.104 0.140 0.079 0.113 0.059 curveto" << endl;
	out_ << "%%postscript	0.069 0.037 0.033 0.077 0.063 0.117 curveto" << endl;
	out_ << "%%postscript	0.082 0.141 0.104 0.117 0.132 0.142 curveto" << endl;
	out_ << "%%postscript	0.153 0.163 0.144 0.188 0.113 0.182 curveto" << endl;
	out_ << "%%postscript	0.073 0.182 0.075 0.147 0.046 0.152 curveto" << endl;
	out_ << "%%postscript	-0.003 0.152 -0.003 0.227 0.048 0.227 curveto" << endl;
	out_ << "%%postscript	0.075 0.231 0.075 0.198 0.113 0.196 curveto" << endl;
	out_ << "%%postscript	0.141 0.197 0.147 0.207 0.133 0.237 curveto" << endl;
	out_ << "%%postscript	0.102 0.264 0.082 0.237 0.062 0.261 curveto" << endl;
	out_ << "%%postscript	0.028 0.302 0.077 0.347 0.118 0.318 curveto" << endl;
	out_ << "%%postscript	0.138 0.297 0.116 0.275 0.144 0.242 curveto" << endl;
	out_ << "%%postscript	fill pop grestore}!" << endl;
	out_ << "%" << endl;
	out_ << "% -- who asked for a Pedal indication ?" << endl;
	out_ << "%%deco ped 6 ped 20 0 0" << endl;
	out_ << "%%deco ped-end 6 pedoff 20 0 0" << endl;
	out_ << "%" << endl;
}
