MuseScore/mscore/importgtp.cpp
2012-05-26 14:49:10 +02:00

2830 lines
98 KiB
C++

//=============================================================================
// MusE Score
// Linux Music Score Editor
// $Id:$
//
// Copyright (C) 2011 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//=============================================================================
#include "importgtp.h"
#include "musescore.h"
#include "libmscore/score.h"
#include "libmscore/measurebase.h"
#include "libmscore/text.h"
#include "libmscore/box.h"
#include "libmscore/staff.h"
#include "libmscore/part.h"
#include "libmscore/measure.h"
#include "libmscore/timesig.h"
#include "libmscore/rest.h"
#include "libmscore/chord.h"
#include "libmscore/note.h"
#include "libmscore/tablature.h"
#include "libmscore/clef.h"
#include "libmscore/lyrics.h"
#include "libmscore/tempotext.h"
#include "libmscore/slur.h"
#include "libmscore/tuplet.h"
#include "libmscore/barline.h"
#include "libmscore/excerpt.h"
#include "libmscore/stafftype.h"
#include "libmscore/bracket.h"
#include "libmscore/articulation.h"
#include "libmscore/keysig.h"
#include "libmscore/harmony.h"
#include "libmscore/bend.h"
#include "libmscore/tremolobar.h"
#include "libmscore/segment.h"
#include "libmscore/rehearsalmark.h"
//---------------------------------------------------------
// errmsg
//---------------------------------------------------------
const char* GuitarPro::errmsg[] = {
"no error",
"unknown file format",
"unexpected end of file",
"bad number of strings",
};
//---------------------------------------------------------
// GpBar
//---------------------------------------------------------
GpBar::GpBar()
{
barLine = NORMAL_BAR;
keysig = GP_INVALID_KEYSIG;
timesig = Fraction(4,4);
repeatFlags = 0;
repeats = 2;
}
//---------------------------------------------------------
// GuitarPro
//---------------------------------------------------------
GuitarPro::GuitarPro(Score* s, int v)
{
score = s;
version = v;
}
GuitarPro::~GuitarPro()
{
}
//---------------------------------------------------------
// skip
//---------------------------------------------------------
void GuitarPro::skip(qint64 len)
{
char c;
while (len--)
read(&c, 1);
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
void GuitarPro::read(void* p, qint64 len)
{
if (len == 0)
return;
qint64 rv = f->read((char*)p, len);
if (rv != len) {
abort();
throw GP_EOF;
}
curPos += len;
}
//---------------------------------------------------------
// readChar
//---------------------------------------------------------
int GuitarPro::readChar()
{
char c;
read(&c, 1);
return c;
}
//---------------------------------------------------------
// readUChar
//---------------------------------------------------------
int GuitarPro::readUChar()
{
uchar c;
read(&c, 1);
return c;
}
//---------------------------------------------------------
// readPascalString
//---------------------------------------------------------
QString GuitarPro::readPascalString(int n)
{
uchar l = readUChar();
char s[l + 1];
read(s, l);
s[l] = 0;
skip(n - l);
return QString(s);
}
//---------------------------------------------------------
// readWordPascalString
//---------------------------------------------------------
QString GuitarPro::readWordPascalString()
{
int l = readInt();
char c[l+1];
read(c, l);
c[l] = 0;
return QString::fromLocal8Bit(c);
}
//---------------------------------------------------------
// readBytePascalString
//---------------------------------------------------------
QString GuitarPro::readBytePascalString()
{
int l = readUChar();
char c[l+1];
read(c, l);
c[l] = 0;
return QString::fromLocal8Bit(c);
}
//---------------------------------------------------------
// readDelphiString
//---------------------------------------------------------
QString GuitarPro::readDelphiString()
{
int maxl = readInt();
uchar l = readUChar();
if (maxl != l + 1) {
qDebug("readDelphiString: first word doesn't match second byte");
abort();
}
char c[l + 1];
read(c, l);
c[l] = 0;
return QString::fromLatin1(c);
}
//---------------------------------------------------------
// readInt
//---------------------------------------------------------
int GuitarPro::readInt()
{
uchar x;
read(&x, 1);
int r = x;
read(&x, 1);
r += x << 8;
read(&x, 1);
r += x << 16;
read(&x, 1);
r += x << 24;
return r;
}
//---------------------------------------------------------
// setTuplet
//---------------------------------------------------------
void GuitarPro::setTuplet(Tuplet* tuplet, int tuple)
{
switch(tuple) {
case 3:
tuplet->setRatio(Fraction(3,2));
break;
case 5:
tuplet->setRatio(Fraction(5,4));
break;
case 6:
tuplet->setRatio(Fraction(6,4));
break;
case 7:
tuplet->setRatio(Fraction(7,4));
break;
case 9:
tuplet->setRatio(Fraction(9,8));
break;
case 10:
tuplet->setRatio(Fraction(10,8));
break;
case 11:
tuplet->setRatio(Fraction(11,8));
break;
case 12:
tuplet->setRatio(Fraction(12,8));
break;
case 13:
tuplet->setRatio(Fraction(13,8));
break;
default:
qDebug("unsupported tuplet %d\n", tuple);
abort();
}
}
//---------------------------------------------------------
// addDynamic
//---------------------------------------------------------
void GuitarPro::addDynamic(Note* /*note*/, int d)
{
if (d == 8) {
// Articulation* a = new Articulation(note->score());
// a->setSubtype(SforzatoaccentSym);
// note->chord()->add(a);
}
else {
// qDebug("dynamic %d\n", d);
}
}
//---------------------------------------------------------
// readBend
// bend graph
//---------------------------------------------------------
void GuitarPro::readBend()
{
readUChar(); // icon
readInt(); // shown aplitude
int n = readInt();
for (int i = 0; i < n; ++i) {
readInt(); // time
readInt(); // pitch
readUChar(); // vibrato
}
}
//---------------------------------------------------------
// readLyrics
//---------------------------------------------------------
void GuitarPro::readLyrics()
{
readInt(); // lyric track
for (int i = 0; i < 5; ++i) {
readInt();
readWordPascalString();
}
}
//---------------------------------------------------------
// readChannels
//---------------------------------------------------------
void GuitarPro::readChannels()
{
for (int i = 0; i < GP_MAX_TRACK_NUMBER * 2; ++i) {
channelDefaults[i].patch = readInt();
channelDefaults[i].volume = readUChar() * 8 - 1;
channelDefaults[i].pan = readUChar() * 8 - 1;
channelDefaults[i].chorus = readUChar() * 8 - 1;
channelDefaults[i].reverb = readUChar() * 8 - 1;
channelDefaults[i].phase = readUChar() * 8 - 1;
channelDefaults[i].tremolo = readUChar() * 8 - 1;
skip(2);
}
}
//---------------------------------------------------------
// len2fraction
//---------------------------------------------------------
Fraction GuitarPro::len2fraction(int len)
{
Fraction l;
switch(len) {
case -2: l.set(1, 1); break;
case -1: l.set(1, 2); break;
case 0: l.set(1, 4); break;
case 1: l.set(1, 8); break;
case 2: l.set(1, 16); break;
case 3: l.set(1, 32); break;
case 4: l.set(1, 64); break;
case 5: l.set(1, 128); break;
//case 6: l.set(1, 512); break;
//case 7: l.set(1, 1024); break;
//case 8: l.set(1, 2048); break;
default:
qDebug("unknown beat len: %d\n", len);
abort();
}
return l;
}
//---------------------------------------------------------
// readMixChange
//---------------------------------------------------------
void GuitarPro::readMixChange()
{
/*char patch =*/ readChar();
char volume = readChar();
char pan = readChar();
char chorus = readChar();
char reverb = readChar();
char phase = readChar();
char tremolo = readChar();
int tempo = readInt();
if (volume >= 0)
readChar();
if (pan >= 0)
readChar();
if (chorus >= 0)
readChar();
if (reverb >= 0)
readChar();
if (phase >= 0)
readChar();
if (tremolo >= 0)
readChar();
if (tempo >= 0)
readChar();
}
//---------------------------------------------------------
// createMeasures
//---------------------------------------------------------
void GuitarPro::createMeasures()
{
int tick = 0;
Fraction ts;
for (int i = 0; i < measures; ++i) {
Fraction nts = bars[i].timesig;
Measure* m = new Measure(score);
m->setTick(tick);
m->setTimesig(nts);
m->setLen(nts);
if (i == 0 || ts != nts) {
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
Staff* staff = score->staff(staffIdx);
StaffType* staffType = staff->staffType();
qDebug("staff %d group %d timesig %d\n", staffIdx, int(staffType->group()), staffType->genTimesig());
if (staffType->genTimesig()) {
TimeSig* t = new TimeSig(score, nts);
t->setTrack(staffIdx * VOICES);
Segment* s = m->getSegment(SegTimeSig, tick);
s->add(t);
}
}
}
if (i == 0 || (bars[i].keysig != GP_INVALID_KEYSIG)) {
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
KeySig* t = new KeySig(score);
int keysig = bars[i].keysig != GP_INVALID_KEYSIG ? bars[i].keysig : key;
t->setSig(0, keysig);
t->setTrack(staffIdx * VOICES);
Segment* s = m->getSegment(SegKeySig, tick);
s->add(t);
}
}
m->setRepeatFlags(bars[i].repeatFlags);
m->setRepeatCount(bars[i].repeats); // supported in gp5
score->add(m);
tick += nts.ticks();
ts = nts;
}
}
//---------------------------------------------------------
// applyBeatEffects
//---------------------------------------------------------
void GuitarPro::applyBeatEffects(Chord* chord, int beatEffect)
{
if (beatEffect == 0)
return;
Articulation* a = new Articulation(chord->score());
chord->add(a);
switch (beatEffect) {
case 1:
a->setSubtype(Articulation_Tapping);
break;
case 2:
a->setSubtype(Articulation_Slapping);
break;
case 3:
a->setSubtype(Articulation_Popping);
break;
default:
qDebug("GuitarPro import: unknown beat effect %d\n", beatEffect);
}
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
void GuitarPro1::read(QFile* fp)
{
f = fp;
curPos = 30;
title = readDelphiString();
artist = readDelphiString();
readDelphiString();
int tempo = readInt();
/*uchar num =*/ readUChar(); // Shuffle rhythm feel
// int octave = 0;
key = 0;
if (version > 102)
key = readInt(); // key
staves = version > 102 ? 8 : 1;
//int tnumerator = 4;
//int tdenominator = 4;
//
// create a part for every staff
//
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
Part* part = new Part(score);
Staff* s = new Staff(score, part, staffIdx);
part->insertStaff(s);
score->staves().push_back(s);
score->appendPart(part);
}
int tick = 0;
Fraction ts;
for (int i = 0; i < staves; ++i) {
int tuning[GP_MAX_STRING_NUMBER];
int strings = version > 101 ? readInt() : 6;
for (int j = 0; j < strings; ++j)
tuning[j] = readInt();
int tuning2[strings];
for (int k = 0; k < strings; ++k)
tuning2[strings-k-1] = tuning[k];
int frets = 32; // TODO
Tablature* tab = new Tablature(frets, strings, tuning2);
Part* part = score->part(i);
Instrument* instr = part->instr();
instr->setTablature(tab);
}
measures = readInt();
for (int i = 0; i < measures; ++i) {
Fraction nts = bars[i].timesig;
Measure* m = new Measure(score);
m->setTick(tick);
m->setTimesig(nts);
m->setLen(nts);
if (i == 0 || ts != nts) {
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
TimeSig* t = new TimeSig(score, nts);
t->setTrack(staffIdx * VOICES);
Segment* s = m->getSegment(SegTimeSig, tick);
s->add(t);
}
}
score->add(m);
tick += nts.ticks();
ts = nts;
}
Measure* measure = score->firstMeasure();
for (int bar = 0; bar < measures; ++bar, measure = measure->nextMeasure()) {
const GpBar& gpbar = bars[bar];
if (!gpbar.marker.isEmpty()) {
Text* s = new RehearsalMark(score);
s->setText(gpbar.marker.trimmed());
s->setTrack(0);
Segment* segment = measure->getSegment(SegChordRest, measure->tick());
segment->add(s);
}
Tuplet* tuplets[staves];
for (int staffIdx = 0; staffIdx < staves; ++staffIdx)
tuplets[staffIdx] = 0;
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
int tick = measure->tick();
int beats = readInt();
for (int beat = 0; beat < beats; ++beat) {
// int pause = 0;
uchar beatBits = readUChar();
bool dotted = beatBits & 0x1;
if (beatBits & 0x40)
/*pause =*/ readUChar();
int len = readChar();
int tuple = 0;
if (beatBits & 0x20)
tuple = readInt();
Segment* segment = measure->getSegment(SegChordRest, tick);
if (beatBits & 0x2)
readChord(segment, staffIdx * VOICES);
Lyrics* lyrics = 0;
if (beatBits & 0x4) {
lyrics = new Lyrics(score);
lyrics->setText(readDelphiString());
}
if (beatBits & 0x8)
readBeatEffects(staffIdx * VOICES, segment);
if (beatBits & 0x10)
readMixChange();
int strings = readUChar(); // used strings mask
Fraction l = len2fraction(len);
ChordRest* cr;
if (strings)
cr = new Chord(score);
else
cr = new Rest(score);
cr->setTrack(staffIdx * VOICES);
if (lyrics)
cr->add(lyrics);
if (tuple) {
Tuplet* tuplet = tuplets[staffIdx];
if ((tuplet == 0) || (tuplet->elements().size() == tuple)) {
tuplet = new Tuplet(score);
tuplet->setTrack(cr->track());
tuplets[staffIdx] = tuplet;
tuplet->setParent(measure);
}
tuplet->setTrack(staffIdx * VOICES);
tuplet->setBaseLen(l);
setTuplet(tuplet, tuple);
cr->setTuplet(tuplet);
tuplet->add(cr); //TODOxxx
}
TDuration d(l);
d.setDots(dotted ? 1 : 0);
if (dotted)
l = l + (l/2);
cr->setDuration(l);
cr->setDurationType(d);
segment->add(cr);
Staff* staff = cr->staff();
int numStrings = staff->part()->instr()->tablature()->strings();
for (int i = 6; i >= 0; --i) {
if (strings & (1 << i) && ((6-i) < numStrings)) {
Note* note = new Note(score);
static_cast<Chord*>(cr)->add(note);
readNote(6-i, note);
note->setTpcFromPitch();
}
}
tick += cr->actualTicks();
}
}
}
setTempo(tempo);
}
//---------------------------------------------------------
// setTempo
//---------------------------------------------------------
void GuitarPro::setTempo(int tempo)
{
TempoText* tt = new TempoText(score);
tt->setTempo(double(tempo)/60.0);
int uc = 0x1d15f;
QChar h(QChar::highSurrogate(uc));
QChar l(QChar::lowSurrogate(uc));
tt->setText(QString("%1%2 = %3 ").arg(h).arg(l).arg(tempo));
tt->setTrack(0);
Measure* measure = score->firstMeasure();
Segment* segment = measure->getSegment(SegChordRest, 0);
segment->add(tt);
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
void GuitarPro2::read(QFile* fp)
{
f = fp;
curPos = 30;
title = readDelphiString();
subtitle = readDelphiString();
artist = readDelphiString();
album = readDelphiString();
composer = readDelphiString();
QString copyright = readDelphiString();
if (!copyright.isEmpty())
score->setMetaTag("Copyright", QString("Copyright %1\nAll Rights Reserved - International Copyright Secured").arg(copyright));
transcriber = readDelphiString();
instructions = readDelphiString();
int n = readInt();
for (int i = 0; i < n; ++i)
comments.append(readDelphiString());
/*uchar num =*/ readUChar(); // Shuffle rhythm feel
int tempo = readInt();
// int octave = 0;
/*int key =*/ readInt(); // key
for (int i = 0; i < GP_MAX_TRACK_NUMBER * 2; ++i) {
channelDefaults[i].patch = readInt();
channelDefaults[i].volume = readUChar() * 8 - 1;
channelDefaults[i].pan = readUChar() * 8 - 1;
channelDefaults[i].chorus = readUChar() * 8 - 1;
channelDefaults[i].reverb = readUChar() * 8 - 1;
channelDefaults[i].phase = readUChar() * 8 - 1;
channelDefaults[i].tremolo = readUChar() * 8 - 1;
readUChar(); // padding
readUChar();
}
measures = readInt();
staves = readInt();
int tnumerator = 4;
int tdenominator = 4;
for (int i = 0; i < measures; ++i) {
GpBar bar;
uchar barBits = readUChar();
if (barBits & 0x1)
tnumerator = readUChar();
if (barBits & 0x2)
tdenominator = readUChar();
if (barBits & 0x4) { // begin reapeat
qDebug("BeginRepeat=============================================\n");
}
if (barBits & 0x8) // number of repeats
/*uchar c =*/ readUChar();
if (barBits & 0x10) // alternative ending to
/*uchar c =*/ readUChar();
if (barBits & 0x20) {
bar.marker = readDelphiString(); // new section?
/*int color =*/ readInt(); // color?
}
if (barBits & 0x40) {
bar.keysig = readUChar();
/*uchar c =*/ readUChar(); // minor
}
if (barBits & 0x80)
bar.barLine = DOUBLE_BAR;
bar.timesig = Fraction(tnumerator, tdenominator);
bars.append(bar);
}
//
// create a part for every staff
//
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
Part* part = new Part(score);
Staff* s = new Staff(score, part, staffIdx);
part->insertStaff(s);
score->staves().push_back(s);
score->appendPart(part);
}
int tick = 0;
Fraction ts;
for (int i = 0; i < measures; ++i) {
Fraction nts = bars[i].timesig;
Measure* m = new Measure(score);
m->setTick(tick);
m->setTimesig(nts);
m->setLen(nts);
if (i == 0 || ts != nts) {
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
TimeSig* t = new TimeSig(score, nts);
t->setTrack(staffIdx * VOICES);
Segment* s = m->getSegment(SegTimeSig, tick);
s->add(t);
}
}
score->add(m);
tick += nts.ticks();
ts = nts;
}
for (int i = 0; i < staves; ++i) {
int tuning[GP_MAX_STRING_NUMBER];
uchar c = readUChar(); // simulations bitmask
if (c & 0x2) { // 12 stringed guitar
}
if (c & 0x4) { // banjo track
}
QString name = readPascalString(40);
int strings = readInt();
if (strings <= 0 || strings > GP_MAX_STRING_NUMBER)
throw GP_BAD_NUMBER_OF_STRINGS ;
for (int j = 0; j < strings; ++j)
tuning[j] = readInt();
for (int j = strings; j < GP_MAX_STRING_NUMBER; ++j)
readInt();
/*int midiPort =*/ readInt(); // - 1;
int midiChannel = readInt() - 1;
/*int midiChannel2 =*/ readInt(); // - 1;
int frets = readInt();
int capo = readInt();
/*int color =*/ readInt();
int tuning2[strings];
for (int k = 0; k < strings; ++k)
tuning2[strings-k-1] = tuning[k];
Tablature* tab = new Tablature(frets, strings, tuning2);
Part* part = score->part(i);
Instrument* instr = part->instr();
instr->setTablature(tab);
part->setPartName(name);
instr->setTranspose(Interval(capo));
part->setLongName(name);
//
// determine clef
//
Staff* staff = score->staff(i);
int patch = channelDefaults[midiChannel].patch;
ClefType clefId = CLEF_G;
if (c & 0x1) {
clefId = CLEF_PERC;
instr->setUseDrumset(true);
staff->setStaffType(score->staffTypes().at(PERCUSSION_STAFF_TYPE));
}
else if (patch >= 24 && patch < 32)
clefId = CLEF_G3;
else if (patch >= 32 && patch < 40)
clefId = CLEF_F8;
Measure* measure = score->firstMeasure();
Clef* clef = new Clef(score);
clef->setClefType(clefId);
clef->setTrack(i * VOICES);
Segment* segment = measure->getSegment(SegClef, 0);
segment->add(clef);
Channel& ch = instr->channel(0);
if (c & 1) {
ch.program = 0;
ch.bank = 128;
}
else {
ch.program = patch;
ch.bank = 0;
}
ch.volume = channelDefaults[midiChannel].volume;
ch.pan = channelDefaults[midiChannel].pan;
ch.chorus = channelDefaults[midiChannel].chorus;
ch.reverb = channelDefaults[midiChannel].reverb;
// missing: phase, tremolo
ch.updateInitList();
}
Measure* measure = score->firstMeasure();
for (int bar = 0; bar < measures; ++bar, measure = measure->nextMeasure()) {
const GpBar& gpbar = bars[bar];
if (!gpbar.marker.isEmpty()) {
Text* s = new RehearsalMark(score);
s->setText(gpbar.marker.trimmed());
s->setTrack(0);
Segment* segment = measure->getSegment(SegChordRest, measure->tick());
segment->add(s);
}
Tuplet* tuplets[staves];
for (int staffIdx = 0; staffIdx < staves; ++staffIdx)
tuplets[staffIdx] = 0;
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
int tick = measure->tick();
int beats = readInt();
for (int beat = 0; beat < beats; ++beat) {
// int pause = 0;
uchar beatBits = readUChar();
bool dotted = beatBits & 0x1;
if (beatBits & 0x40)
/*pause =*/ readUChar();
int len = readChar();
int tuple = 0;
if (beatBits & 0x20)
tuple = readInt();
Segment* segment = measure->getSegment(SegChordRest, tick);
if (beatBits & 0x2)
readChord(segment, staffIdx * VOICES);
Lyrics* lyrics = 0;
if (beatBits & 0x4) {
QString txt = readDelphiString();
lyrics = new Lyrics(score);
lyrics->setText(txt);
}
if (beatBits & 0x8)
readBeatEffects(staffIdx * VOICES, segment);
if (beatBits & 0x10)
readMixChange();
int strings = readUChar(); // used strings mask
Fraction l = len2fraction(len);
ChordRest* cr;
if (strings)
cr = new Chord(score);
else
cr = new Rest(score);
cr->setTrack(staffIdx * VOICES);
if (lyrics)
cr->add(lyrics);
if (tuple) {
Tuplet* tuplet = tuplets[staffIdx];
if ((tuplet == 0) || (tuplet->elements().size() == tuple)) {
tuplet = new Tuplet(score);
tuplet->setTrack(cr->track());
tuplets[staffIdx] = tuplet;
tuplet->setParent(measure);
}
tuplet->setTrack(staffIdx * VOICES);
tuplet->setBaseLen(l);
setTuplet(tuplet, tuple);
cr->setTuplet(tuplet);
tuplet->add(cr);
}
TDuration d(l);
d.setDots(dotted ? 1 : 0);
if (dotted)
l = l + (l/2);
cr->setDuration(l);
cr->setDurationType(d);
segment->add(cr);
Staff* staff = cr->staff();
int numStrings = staff->part()->instr()->tablature()->strings();
for (int i = 6; i >= 0; --i) {
if (strings & (1 << i) && ((6-i) < numStrings)) {
Note* note = new Note(score);
static_cast<Chord*>(cr)->add(note);
readNote(6-i, note);
note->setTpcFromPitch();
}
}
tick += cr->actualTicks();
}
}
}
setTempo(tempo);
}
//---------------------------------------------------------
// readNote
//---------------------------------------------------------
void GuitarPro1::readNote(int string, Note* note)
{
uchar noteBits = readUChar();
bool tieNote = false;
uchar variant = 1;
if (noteBits & 0x20) {
variant = readUChar();
if (variant == 1) { // normal note
}
else if (variant == 2)
tieNote = true;
else if (variant == 3) { // dead notes
qDebug("DeathNote tick %d pitch %d\n", note->chord()->segment()->tick(), note->pitch());
}
else
qDebug("unknown note variant: %d\n", variant);
}
//
// noteBits:
// 7 - Right hand or left hand fingering;
// 6 - Accentuated note
// 5 - Note type (rest, empty note, normal note);
// 4 - note dynamic;
// 3 - Presence of effects linked to the note;
// 2 - Ghost note;
// 1 - Dotted note; ?
// 0 - Time-independent duration
if (noteBits & 0x1) { // note != beat
int a = readUChar(); // length
int b = readUChar(); // t
qDebug("Time independend note len, len %d t %d\n", a, b);
}
if (noteBits & 0x2) { // note is dotted
}
if (noteBits & 0x10) {
int d = readUChar(); // dynamic
addDynamic(note, d);
}
int fretNumber = -1;
if (noteBits & 0x20)
fretNumber = readUChar();
if (noteBits & 0x80) { // fingering
int a = readUChar();
int b = readUChar();
qDebug("Fingering=========%d %d\n", a, b);
}
if (noteBits & 0x8) {
uchar modMask1 = readUChar();
uchar modMask2 = 0;
if (version >= 400)
modMask2 = readUChar();
if (modMask1 & 0x1)
readBend();
if (modMask1 & 0x2) { // hammer on / pull off
}
if (modMask1 & 0x8) { // let ring
}
if (modMask1 & 0x10) {
readUChar(); // grace fret
readUChar(); // grace dynamic
readUChar(); // grace transition
readUChar(); // grace length
}
if (version >= 400) {
if (modMask2 & 0x1) { // staccato - palm mute
}
if (modMask2 & 0x2) { // palm mute - mute the whole column
}
if (modMask2 & 0x4) // tremolo picking length
readUChar();
if (modMask2 & 0x8)
readUChar(); // slide kind
if (modMask2 & 0x10)
readUChar(); // harmonic kind
if (modMask2 & 0x20) {
readUChar(); // trill fret
readUChar(); // trill length
}
}
}
if (fretNumber == -1) {
qDebug("Note: no fret number, tie %d\n", tieNote);
}
Staff* staff = note->staff();
if (fretNumber == 255) {
fretNumber = 0;
note->setHeadGroup(HEAD_CROSS);
note->setGhost(true);
}
int pitch = staff->part()->instr()->tablature()->getPitch(string, fretNumber);
note->setFret(fretNumber);
note->setString(string);
note->setPitch(pitch);
if (tieNote) {
bool found = false;
Chord* chord = note->chord();
Segment* segment = chord->segment()->prev1(SegChordRest);
int track = note->track();
while (segment) {
Element* e = segment->element(track);
if (e) {
if (e->type() == CHORD) {
Chord* chord2 = static_cast<Chord*>(e);
foreach(Note* note2, chord2->notes()) {
if (note2->string() == string) {
Tie* tie = new Tie(score);
tie->setEndNote(note);
note2->add(tie);
note->setFret(note2->fret());
note->setPitch(note2->pitch());
found = true;
break;
}
}
}
if (found)
break;
}
segment = segment->prev1(SegChordRest);
}
if (!found)
qDebug("tied note not found, pitch %d fret %d string %d\n", note->pitch(), note->fret(), note->string());
}
}
//---------------------------------------------------------
// readBeatEffects
//---------------------------------------------------------
int GuitarPro1::readBeatEffects(int, Segment*)
{
uchar fxBits1 = readUChar();
if (fxBits1 & 0x20) {
uchar num = readUChar();
switch(num) {
case 0: // tremolo bar
readInt();
break;
default:
readInt();
break;
}
}
if (fxBits1 & 0x40) {
readUChar(); // down stroke length
readUChar(); // up stroke length
}
return 0;
}
//---------------------------------------------------------
// readChord
//---------------------------------------------------------
void GuitarPro1::readChord(Segment* seg, int track)
{
int header = readUChar();
QString name;
if ((header & 1) == 0) {
name = readDelphiString();
int firstFret = readInt();
if (firstFret) {
for (int i = 0; i < 6; ++i)
readInt();
}
}
else {
skip(25);
name = readPascalString(34);
/*int firstFret =*/ readInt();
for (int i = 0; i < 6; ++i) {
/*int fret =*/ readInt();
}
skip(36);
}
if (name.isEmpty())
return;
Harmony* harmony = new Harmony(seg->score());
harmony->setHarmony(name);
harmony->setTrack(track);
seg->add(harmony);
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
void GuitarPro3::read(QFile* fp)
{
f = fp;
curPos = 30;
title = readDelphiString();
subtitle = readDelphiString();
artist = readDelphiString();
album = readDelphiString();
composer = readDelphiString();
QString copyright = readDelphiString();
if (!copyright.isEmpty())
score->setMetaTag("Copyright", QString("Copyright %1\nAll Rights Reserved - International Copyright Secured").arg(copyright));
transcriber = readDelphiString();
instructions = readDelphiString();
int n = readInt();
for (int i = 0; i < n; ++i)
comments.append(readDelphiString());
/*uchar num =*/ readUChar(); // Shuffle rhythm feel
int tempo = readInt();
// int octave = 0;
key = readInt(); // key
for (int i = 0; i < GP_MAX_TRACK_NUMBER * 2; ++i) {
channelDefaults[i].patch = readInt();
channelDefaults[i].volume = readUChar() * 8 - 1;
channelDefaults[i].pan = readUChar() * 8 - 1;
channelDefaults[i].chorus = readUChar() * 8 - 1;
channelDefaults[i].reverb = readUChar() * 8 - 1;
channelDefaults[i].phase = readUChar() * 8 - 1;
channelDefaults[i].tremolo = readUChar() * 8 - 1;
readUChar(); // padding
readUChar();
}
measures = readInt();
staves = readInt();
int tnumerator = 4;
int tdenominator = 4;
for (int i = 0; i < measures; ++i) {
GpBar bar;
uchar barBits = readUChar();
if (barBits & 0x1)
tnumerator = readUChar();
if (barBits & 0x2)
tdenominator = readUChar();
if (barBits & 0x4) { // begin reapeat
qDebug("BeginRepeat=============================================\n");
}
if (barBits & 0x8) // number of repeats
/*uchar c =*/ readUChar();
if (barBits & 0x10) // alternative ending to
/*uchar c =*/ readUChar();
if (barBits & 0x20) {
bar.marker = readDelphiString(); // new section?
/*int color =*/ readInt(); // color?
}
if (barBits & 0x40) {
bar.keysig = readUChar();
/*uchar c =*/ readUChar(); // minor
}
if (barBits & 0x80)
bar.barLine = DOUBLE_BAR;
bar.timesig = Fraction(tnumerator, tdenominator);
bars.append(bar);
}
//
// create a part for every staff
//
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
Part* part = new Part(score);
Staff* s = new Staff(score, part, staffIdx);
part->insertStaff(s);
score->staves().push_back(s);
score->appendPart(part);
}
int tick = 0;
Fraction ts;
for (int i = 0; i < measures; ++i) {
Fraction nts = bars[i].timesig;
Measure* m = new Measure(score);
m->setTick(tick);
m->setTimesig(nts);
m->setLen(nts);
if (i == 0 || ts != nts) {
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
TimeSig* t = new TimeSig(score, nts);
t->setTrack(staffIdx * VOICES);
Segment* s = m->getSegment(SegTimeSig, tick);
s->add(t);
}
}
if (i == 0 && key) {
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
KeySig* t = new KeySig(score);
t->setSig(0, key);
t->setTrack(staffIdx * VOICES);
Segment* s = m->getSegment(SegKeySig, tick);
s->add(t);
}
}
score->add(m);
tick += nts.ticks();
ts = nts;
}
for (int i = 0; i < staves; ++i) {
int tuning[GP_MAX_STRING_NUMBER];
uchar c = readUChar(); // simulations bitmask
if (c & 0x2) { // 12 stringed guitar
}
if (c & 0x4) { // banjo track
}
QString name = readPascalString(40);
int strings = readInt();
if (strings <= 0 || strings > GP_MAX_STRING_NUMBER)
throw GP_BAD_NUMBER_OF_STRINGS ;
for (int j = 0; j < strings; ++j)
tuning[j] = readInt();
for (int j = strings; j < GP_MAX_STRING_NUMBER; ++j)
readInt();
/*int midiPort =*/ readInt(); // - 1;
int midiChannel = readInt() - 1;
/*int midiChannel2 =*/ readInt(); // - 1;
int frets = readInt();
int capo = readInt();
/*int color =*/ readInt();
int tuning2[strings];
for (int k = 0; k < strings; ++k)
tuning2[strings-k-1] = tuning[k];
Tablature* tab = new Tablature(frets, strings, tuning2);
Part* part = score->part(i);
Instrument* instr = part->instr();
instr->setTablature(tab);
part->setPartName(name);
part->setLongName(name);
instr->setTranspose(Interval(capo));
//
// determine clef
//
Staff* staff = score->staff(i);
int patch = channelDefaults[midiChannel].patch;
ClefType clefId = CLEF_G;
if (c & 0x1) {
clefId = CLEF_PERC;
instr->setUseDrumset(true);
staff->setStaffType(score->staffTypes().at(PERCUSSION_STAFF_TYPE));
}
else if (patch >= 24 && patch < 32)
clefId = CLEF_G3;
else if (patch >= 32 && patch < 40)
clefId = CLEF_F8;
Measure* measure = score->firstMeasure();
Clef* clef = new Clef(score);
clef->setClefType(clefId);
clef->setTrack(i * VOICES);
Segment* segment = measure->getSegment(SegClef, 0);
segment->add(clef);
Channel& ch = instr->channel(0);
if (c & 1) {
ch.program = 0;
ch.bank = 128;
}
else {
ch.program = patch;
ch.bank = 0;
}
ch.volume = channelDefaults[midiChannel].volume;
ch.pan = channelDefaults[midiChannel].pan;
ch.chorus = channelDefaults[midiChannel].chorus;
ch.reverb = channelDefaults[midiChannel].reverb;
// missing: phase, tremolo
ch.updateInitList();
}
Measure* measure = score->firstMeasure();
for (int bar = 0; bar < measures; ++bar, measure = measure->nextMeasure()) {
const GpBar& gpbar = bars[bar];
if (!gpbar.marker.isEmpty()) {
Text* s = new RehearsalMark(score);
s->setText(gpbar.marker.trimmed());
s->setTrack(0);
Segment* segment = measure->getSegment(SegChordRest, measure->tick());
segment->add(s);
}
Tuplet* tuplets[staves];
for (int staffIdx = 0; staffIdx < staves; ++staffIdx)
tuplets[staffIdx] = 0;
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
int tick = measure->tick();
int beats = readInt();
for (int beat = 0; beat < beats; ++beat) {
// int pause = 0;
uchar beatBits = readUChar();
bool dotted = beatBits & 0x1;
if (beatBits & 0x40)
/*pause =*/ readUChar();
int len = readChar();
int tuple = 0;
if (beatBits & 0x20)
tuple = readInt();
Segment* segment = measure->getSegment(SegChordRest, tick);
if (beatBits & 0x2)
readChord(segment, staffIdx * VOICES);
Lyrics* lyrics = 0;
if (beatBits & 0x4) {
QString txt = readDelphiString();
lyrics = new Lyrics(score);
lyrics->setText(txt);
}
if (beatBits & 0x8)
readBeatEffects(staffIdx * VOICES, segment);
if (beatBits & 0x10)
readMixChange();
int strings = readUChar(); // used strings mask
Fraction l;
switch(len) {
case -2: l.set(1, 1); break;
case -1: l.set(1, 2); break;
case 0: l.set(1, 4); break;
case 1: l.set(1, 8); break;
case 2: l.set(1, 16); break;
case 3: l.set(1, 32); break;
case 4: l.set(1, 64); break;
case 5: l.set(1, 128); break;
//case 6: l.set(1, 512); break;
//case 7: l.set(1, 1024); break;
//case 8: l.set(1, 2048); break;
default:
qDebug("unknown beat len: %d\n", len);
abort();
}
ChordRest* cr;
// if (!pause || strings)
if (strings)
cr = new Chord(score);
else
cr = new Rest(score);
cr->setTrack(staffIdx * VOICES);
if (lyrics)
cr->add(lyrics);
if (tuple) {
Tuplet* tuplet = tuplets[staffIdx];
if ((tuplet == 0) || (tuplet->elements().size() == tuple)) {
tuplet = new Tuplet(score);
tuplet->setTrack(cr->track());
tuplets[staffIdx] = tuplet;
tuplet->setParent(measure);
}
tuplet->setTrack(staffIdx * VOICES);
tuplet->setBaseLen(l);
setTuplet(tuplet, tuple);
cr->setTuplet(tuplet);
tuplet->add(cr);
}
TDuration d(l);
d.setDots(dotted ? 1 : 0);
if (dotted)
l = l + (l/2);
cr->setDuration(l);
cr->setDurationType(d);
segment->add(cr);
Staff* staff = cr->staff();
int numStrings = staff->part()->instr()->tablature()->strings();
for (int i = 6; i >= 0; --i) {
if (strings & (1 << i) && ((6-i) < numStrings)) {
Note* note = new Note(score);
static_cast<Chord*>(cr)->add(note);
readNote(6-i, note);
note->setTpcFromPitch();
}
}
tick += cr->actualTicks();
}
}
}
setTempo(tempo);
}
//---------------------------------------------------------
// readBend
// bend graph
//---------------------------------------------------------
void GuitarPro4::readBend()
{
skip(5);
int n = readInt();
for (int i = 0; i < n; ++i) {
readInt(); // time position
readInt(); // pitch
readUChar(); // vibrato
}
}
//---------------------------------------------------------
// readMixChange
//---------------------------------------------------------
void GuitarPro4::readMixChange()
{
/*char patch =*/ readChar();
char volume = readChar();
char pan = readChar();
char chorus = readChar();
char reverb = readChar();
char phase = readChar();
char tremolo = readChar();
int tempo = readInt();
if (volume >= 0)
readChar();
if (pan >= 0)
readChar();
if (chorus >= 0)
readChar();
if (reverb >= 0)
readChar();
if (phase >= 0)
readChar();
if (tremolo >= 0)
readChar();
if (tempo >= 0)
readChar();
readChar(); // bitmask: what should be applied to all tracks
}
//---------------------------------------------------------
// readBeatEffects
//---------------------------------------------------------
int GuitarPro4::readBeatEffects(int, Segment*)
{
int effects = 0;
uchar fxBits1 = readUChar();
uchar fxBits2 = readUChar();
if (fxBits1 & 0x20) {
effects = readUChar(); // effect 1-tapping, 2-slapping, 3-popping
}
if (fxBits2 & 0x04)
readBend();
if (fxBits1 & 0x40) {
readUChar(); // down stroke length
readUChar(); // up stroke length
}
if (fxBits2 & 0x02)
readUChar(); // stroke pick direction
if (fxBits1 & 0x01) { // GP3 column-wide vibrato
}
if (fxBits1 & 0x2) { // GP3 column-wide wide vibrato (="tremolo" in GP3)
}
return effects;
}
//---------------------------------------------------------
// readNote
//---------------------------------------------------------
void GuitarPro4::readNote(int string, Note* note, GpNote* gpNote)
{
uchar noteBits = readUChar();
//
// noteBits:
// 7 - Right hand or left hand fingering;
// 6 - Accentuated note
// 5 - Note type (rest, empty note, normal note);
// 4 - note dynamic;
// 3 - Presence of effects linked to the note;
// 2 - Ghost note;
// 1 - Dotted note; ?
// 0 - Time-independent duration
bool tieNote = false;
uchar variant = 1;
if (noteBits & 0x20) {
variant = readUChar();
if (variant == 1) { // normal note
}
else if (variant == 2)
tieNote = true;
else if (variant == 3) { // dead notes
//qDebug("DeathNote tick %d pitch %d\n", note->chord()->segment()->tick(), note->pitch());
}
else
qDebug("unknown note variant: %d\n", variant);
}
if (noteBits & 0x1) { // note != beat
int a = readUChar(); // length
int b = readUChar(); // t
qDebug(" Time independend note len, len %d t %d\n", a, b);
}
if (noteBits & 0x2) { // note is dotted
}
if (noteBits & 0x10) {
int d = readUChar(); // dynamic
addDynamic(note, d);
}
int fretNumber = -1;
if (noteBits & 0x20)
fretNumber = readUChar();
if (noteBits & 0x80) { // fingering
int a = readUChar();
int b = readUChar();
qDebug("Fingering=========%d %d\n", a, b);
}
gpNote->slur = false;
if (noteBits & 0x8) {
uchar modMask1 = readUChar();
uchar modMask2 = readUChar();
if (modMask1 & 0x1)
readBend();
if (modMask1 & 0x2) { // hammer on / pull off
gpNote->slur = true;
}
if (modMask1 & 0x8) { // let ring
}
if (modMask1 & 0x10) {
readUChar(); // grace fret
readUChar(); // grace dynamic
readUChar(); // grace transition
readUChar(); // grace length
}
if (modMask2 & 0x1) { // staccato
}
if (modMask2 & 0x2) { // palm mute - mute the whole column
}
if (modMask2 & 0x4) // tremolo picking length
readUChar();
if (modMask2 & 0x8)
readUChar(); // slide kind
if (modMask2 & 0x10)
readUChar(); // harmonic kind
if (modMask2 & 0x20) {
readUChar(); // trill fret
readUChar(); // trill length
}
}
if (fretNumber == -1) {
qDebug("Note: no fret number, tie %d\n", tieNote);
}
Staff* staff = note->staff();
if (fretNumber == 255) {
fretNumber = 0;
note->setHeadGroup(HEAD_CROSS);
note->setGhost(true);
}
int pitch = staff->part()->instr()->tablature()->getPitch(string, fretNumber);
note->setFret(fretNumber);
note->setString(string);
note->setPitch(pitch);
if (tieNote) {
bool found = false;
Chord* chord = note->chord();
Segment* segment = chord->segment()->prev1(SegChordRest);
int track = note->track();
while (segment) {
Element* e = segment->element(track);
if (e) {
if (e->type() == CHORD) {
Chord* chord2 = static_cast<Chord*>(e);
foreach(Note* note2, chord2->notes()) {
if (note2->string() == string) {
Tie* tie = new Tie(score);
tie->setEndNote(note);
note2->add(tie);
note->setFret(note2->fret());
note->setPitch(note2->pitch());
found = true;
break;
}
}
}
if (found)
break;
}
segment = segment->prev1(SegChordRest);
}
if (!found)
qDebug("tied note not found, pitch %d fret %d string %d\n", note->pitch(), note->fret(), note->string());
}
}
//---------------------------------------------------------
// readInfo
//---------------------------------------------------------
void GuitarPro4::readInfo()
{
title = readDelphiString();
subtitle = readDelphiString();
artist = readDelphiString();
album = readDelphiString();
composer = readDelphiString();
QString copyright = readDelphiString();
if (!copyright.isEmpty())
score->setMetaTag("Copyright", QString("Copyright %1\nAll Rights Reserved - International Copyright Secured").arg(copyright));
transcriber = readDelphiString();
instructions = readDelphiString();
int n = readInt();
for (int i = 0; i < n; ++i)
comments.append(readDelphiString());
}
//---------------------------------------------------------
// readChord
//---------------------------------------------------------
void GuitarPro4::readChord(Segment* seg, int track)
{
int header = readUChar();
QString name;
if ((header & 1) == 0) {
name = readDelphiString();
int firstFret = readInt();
if (firstFret != 0) {
for (int i = 0; i < 6; ++i) {
readInt();
}
}
}
else {
skip(16);
name = readPascalString(21);
skip(4);
/*int firstFret =*/ readInt();
for (int i = 0; i < 7; ++i)
readInt();
skip(32);
}
if (name.isEmpty())
return;
Harmony* harmony = new Harmony(seg->score());
harmony->setHarmony(name);
harmony->setTrack(track);
seg->add(harmony);
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
void GuitarPro4::read(QFile* fp)
{
f = fp;
curPos = 30;
readInfo();
readUChar(); // triplet feeling
readLyrics();
int tempo = readInt();
key = readInt();
/*int octave =*/ readUChar(); // octave
readChannels();
measures = readInt();
staves = readInt();
int tnumerator = 4;
int tdenominator = 4;
for (int i = 0; i < measures; ++i) {
GpBar bar;
uchar barBits = readUChar();
if (barBits & 0x1)
tnumerator = readUChar();
if (barBits & 0x2)
tdenominator = readUChar();
if (barBits & 0x4)
bar.repeatFlags |= RepeatStart;
if (barBits & 0x8) { // number of repeats
bar.repeatFlags |= RepeatEnd;
bar.repeats = readUChar();
}
if (barBits & 0x10) // alternative ending to
/*uchar c =*/ readUChar();
if (barBits & 0x20) {
bar.marker = readDelphiString(); // new section?
/*int color = */ readInt(); // color?
}
if (barBits & 0x40) {
bar.keysig = readUChar();
readUChar(); // minor
}
if (barBits & 0x80)
bar.barLine = DOUBLE_BAR;
bar.timesig = Fraction(tnumerator, tdenominator);
bars.append(bar);
}
//
// create a part for every staff
//
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
Part* part = new Part(score);
Staff* s = new Staff(score, part, staffIdx);
part->insertStaff(s);
score->staves().push_back(s);
score->appendPart(part);
}
createMeasures();
for (int i = 0; i < staves; ++i) {
int tuning[GP_MAX_STRING_NUMBER];
uchar c = readUChar(); // simulations bitmask
if (c & 0x2) { // 12 stringed guitar
}
if (c & 0x4) { // banjo track
}
QString name = readPascalString(40);
int strings = readInt();
if (strings <= 0 || strings > GP_MAX_STRING_NUMBER)
throw GP_BAD_NUMBER_OF_STRINGS ;
for (int j = 0; j < strings; ++j)
tuning[j] = readInt();
for (int j = strings; j < GP_MAX_STRING_NUMBER; ++j)
readInt();
/*int midiPort =*/ readInt(); // - 1;
int midiChannel = readInt() - 1;
/*int midiChannel2 =*/ readInt(); // - 1;
int frets = readInt();
int capo = readInt();
/*int color =*/ readInt();
int tuning2[strings];
for (int k = 0; k < strings; ++k)
tuning2[strings-k-1] = tuning[k];
Tablature* tab = new Tablature(frets, strings, tuning2);
Part* part = score->part(i);
Instrument* instr = part->instr();
instr->setTablature(tab);
part->setPartName(name);
instr->setTranspose(Interval(capo));
part->setLongName(name);
//
// determine clef
//
Staff* staff = score->staff(i);
int patch = channelDefaults[midiChannel].patch;
ClefType clefId = CLEF_G;
if (c & 0x1) {
clefId = CLEF_PERC;
instr->setUseDrumset(true);
staff->setStaffType(score->staffTypes().at(PERCUSSION_STAFF_TYPE));
}
else if (patch >= 24 && patch < 32)
clefId = CLEF_G3;
else if (patch >= 32 && patch < 40)
clefId = CLEF_F8;
Measure* measure = score->firstMeasure();
Clef* clef = new Clef(score);
clef->setClefType(clefId);
clef->setTrack(i * VOICES);
Segment* segment = measure->getSegment(SegClef, 0);
segment->add(clef);
Channel& ch = instr->channel(0);
if (c & 1) {
ch.program = 0;
ch.bank = 128;
}
else {
ch.program = patch;
ch.bank = 0;
}
ch.volume = channelDefaults[midiChannel].volume;
ch.pan = channelDefaults[midiChannel].pan;
ch.chorus = channelDefaults[midiChannel].chorus;
ch.reverb = channelDefaults[midiChannel].reverb;
// missing: phase, tremolo
ch.updateInitList();
}
Slur* slurs[staves];
for (int i = 0; i < staves; ++i)
slurs[i] = 0;
Measure* measure = score->firstMeasure();
for (int bar = 0; bar < measures; ++bar, measure = measure->nextMeasure()) {
const GpBar& gpbar = bars[bar];
if (!gpbar.marker.isEmpty()) {
Text* s = new RehearsalMark(score);
s->setText(gpbar.marker.trimmed());
s->setTrack(0);
Segment* segment = measure->getSegment(SegChordRest, measure->tick());
segment->add(s);
}
Tuplet* tuplets[staves];
for (int staffIdx = 0; staffIdx < staves; ++staffIdx)
tuplets[staffIdx] = 0;
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
int tick = measure->tick();
int beats = readInt();
for (int beat = 0; beat < beats; ++beat) {
uchar beatBits = readUChar();
bool dotted = beatBits & 0x1;
int pause = -1;
if (beatBits & 0x40)
pause = readUChar();
int len = readChar();
int tuple = 0;
if (beatBits & 0x20)
tuple = readInt();
Segment* segment = measure->getSegment(SegChordRest, tick);
if (beatBits & 0x2)
readChord(segment, staffIdx * VOICES);
Lyrics* lyrics = 0;
if (beatBits & 0x4) {
lyrics = new Lyrics(score);
lyrics->setText(readDelphiString());
}
if (beatBits & 0x8)
readBeatEffects(staffIdx * VOICES, segment);
if (beatBits & 0x10)
readMixChange();
int strings = readUChar(); // used strings mask
Fraction l = len2fraction(len);
ChordRest* cr;
if (strings == 0)
cr = new Rest(score);
else
cr = new Chord(score);
cr->setTrack(staffIdx * VOICES);
if (lyrics)
cr->add(lyrics);
if (tuple) {
Tuplet* tuplet = tuplets[staffIdx];
if ((tuplet == 0) || (tuplet->elements().size() == tuple)) {
tuplet = new Tuplet(score);
tuplet->setTrack(cr->track());
tuplets[staffIdx] = tuplet;
tuplet->setParent(measure);
}
tuplet->setTrack(staffIdx * VOICES);
tuplet->setBaseLen(l);
setTuplet(tuplet, tuple);
cr->setTuplet(tuplet);
tuplet->add(cr);
}
TDuration d(l);
d.setDots(dotted ? 1 : 0);
if (dotted)
l = l + (l/2);
cr->setDuration(l);
if (cr->type() == REST && (pause == 0 || l == measure->len()))
cr->setDurationType(TDuration::V_MEASURE);
else
cr->setDurationType(d);
segment->add(cr);
Staff* staff = cr->staff();
int numStrings = staff->part()->instr()->tablature()->strings();
bool hasSlur = false;
for (int i = 6; i >= 0; --i) {
if (strings & (1 << i) && ((6-i) < numStrings)) {
Note* note = new Note(score);
static_cast<Chord*>(cr)->add(note);
GpNote gpNote;
readNote(6-i, note, &gpNote);
if (gpNote.slur)
hasSlur = true;
note->setTpcFromPitch();
}
}
if (hasSlur && (slurs[staffIdx] == 0)) {
Slur* slur = new Slur(score);
slur->setParent(0);
slur->setTrack(staffIdx * VOICES);
slur->setStartElement(cr);
slur->setEndElement(cr);
slurs[staffIdx] = slur;
}
else if (slurs[staffIdx] && !hasSlur) {
// TODO: check slur
Slur* s = slurs[staffIdx];
slurs[staffIdx] = 0;
s->setEndElement(cr);
static_cast<Chord*>(s->startElement())->addSlurFor(s);
static_cast<Chord*>(s->endElement())->addSlurBack(s);
}
else if (slurs[staffIdx] && hasSlur) {
}
tick += cr->actualTicks();
}
}
}
setTempo(tempo);
}
//---------------------------------------------------------
// readInfo
//---------------------------------------------------------
void GuitarPro5::readInfo()
{
title = readDelphiString();
subtitle = readDelphiString();
artist = readDelphiString();
album = readDelphiString();
composer = readDelphiString();
readDelphiString();
QString copyright = readDelphiString();
if (!copyright.isEmpty())
score->setMetaTag("Copyright", QString("Copyright %1\nAll Rights Reserved - International Copyright Secured").arg(copyright));
transcriber = readDelphiString();
instructions = readDelphiString();
int n = readInt();
for (int i = 0; i < n; ++i)
comments.append(readDelphiString());
}
//---------------------------------------------------------
// readNoteEffects
//---------------------------------------------------------
void GuitarPro5::readNoteEffects(Note* note)
{
uchar modMask1 = readUChar();
uchar modMask2 = readUChar();
if (modMask1 & 0x1)
readBend(note);
if (modMask1 & 0x2) { // hammer on / pull off
}
if (modMask1 & 0x8) { // let ring
}
if (modMask1 & 0x10) {
readUChar(); // grace fret
readUChar(); // grace dynamic
readUChar(); // grace transition
readUChar(); // grace length
/*int flags =*/ readUChar();
// 1 - dead
// 2 - on beat
}
if (modMask2 & 0x1) { // staccato - palm mute
Chord* chord = note->chord();
Articulation* a = new Articulation(chord->score());
a->setSubtype(Articulation_Staccato);
chord->add(a);
}
if (modMask2 & 0x2) { // palm mute - mute the whole column
}
if (modMask2 & 0x4) // tremolo picking length
readUChar();
if (modMask2 & 0x8)
readUChar(); // slide kind
if (modMask2 & 0x10)
readArtificialHarmonic();
if (modMask2 & 0x20) {
readUChar(); // trill fret
int period = readUChar(); // trill length
switch(period) {
case 1: // 16
break;
case 2: // 32
break;
case 3: // 64
break;
default:
qDebug("unknown trill period %d\n", period);
break;
}
}
}
//---------------------------------------------------------
// readNote
//---------------------------------------------------------
void GuitarPro5::readNote(int string, Note* note)
{
uchar noteBits = readUChar();
//
// noteBits:
// 7 - Right hand or left hand fingering;
// 6 - Accentuated note
// 5 - Note type (rest, empty note, normal note);
// 4 - note dynamic;
// 3 - Presence of effects linked to the note;
// 2 - Ghost note;
// 1 - Dotted note; ?
// 0 - Time-independent duration
bool tieNote = false;
if (noteBits & 0x20) {
uchar noteType = readUChar();
if (noteType == 1) { // normal note
}
else if (noteType == 2)
tieNote = true;
else if (noteType == 3) { // dead notes
//qDebug("DeathNote tick %d pitch %d\n", note->chord()->segment()->tick(), note->pitch());
}
else
qDebug("unknown note type: %d\n", noteType);
}
if (noteBits & 0x10) { // velocity
int d = readChar();
addDynamic(note, d);
}
int fretNumber = 0;
if (noteBits & 0x20)
fretNumber = readChar();
if (noteBits & 0x80) { // fingering
int a = readUChar();
int b = readUChar();
qDebug(" Fingering=========%d %d\n", a, b);
}
if (noteBits & 0x1)
skip(8);
/*int aa =*/ readUChar();
if (noteBits & 0x8) {
readNoteEffects(note);
}
Staff* staff = note->staff();
if (fretNumber == 255) {
fretNumber = 0;
note->setHeadGroup(HEAD_CROSS);
note->setGhost(true);
}
int pitch = staff->part()->instr()->tablature()->getPitch(string, fretNumber);
note->setFret(fretNumber);
note->setString(string);
note->setPitch(pitch);
if (tieNote) {
bool found = false;
Chord* chord = note->chord();
Segment* segment = chord->segment()->prev1(SegChordRest);
int track = note->track();
while (segment) {
Element* e = segment->element(track);
if (e) {
if (e->type() == CHORD) {
Chord* chord2 = static_cast<Chord*>(e);
foreach(Note* note2, chord2->notes()) {
if (note2->string() == string) {
Tie* tie = new Tie(score);
tie->setEndNote(note);
note2->add(tie);
note->setFret(note2->fret());
note->setPitch(note2->pitch());
found = true;
break;
}
}
}
if (found)
break;
}
segment = segment->prev1(SegChordRest);
}
if (!found)
qDebug("tied note not found, pitch %d fret %d string %d\n", note->pitch(), note->fret(), note->string());
}
}
//---------------------------------------------------------
// readArtificialHarmonic
//---------------------------------------------------------
void GuitarPro5::readArtificialHarmonic()
{
int type = readChar();
switch(type) {
case 1: // natural
break;
case 2: // artificial
skip(3);
break;
case 3: // tapped
skip(1);
break;
case 4: // pinch
break;
case 5: // semi
break;
}
}
//---------------------------------------------------------
// readBend
//---------------------------------------------------------
void GuitarPro5::readBend(Note* note)
{
/*int a1 =*/ readChar();
/*int a2 =*/ readChar();
/*int a3 =*/ readChar();
/*int a4 =*/ readChar();
/*int a5 =*/ readChar();
int n = readInt();
QList<PitchValue> points;
for (int i = 0; i < n; ++i) {
int time = readInt();
int pitch = readInt();
int vibrato = readUChar();
points.append(PitchValue(time, pitch, vibrato));
}
Bend* b = new Bend(note->score());
b->setPoints(points);
b->setTrack(note->track());
note->add(b);
}
//---------------------------------------------------------
// readTremoloBar
//---------------------------------------------------------
void GuitarPro5::readTremoloBar(int track, Segment* segment)
{
/*int a1 =*/ readChar();
/*int a2 =*/ readChar();
/*int a3 =*/ readChar();
/*int a4 =*/ readChar();
/*int a5 =*/ readChar();
int n = readInt();
QList<PitchValue> points;
for (int i = 0; i < n; ++i) {
int time = readInt();
int pitch = readInt();
int vibrato = readUChar();
points.append(PitchValue(time, pitch, vibrato));
}
TremoloBar* b = new TremoloBar(segment->score());
b->setPoints(points);
b->setTrack(track);
segment->add(b);
}
//---------------------------------------------------------
// readBeatEffects
//---------------------------------------------------------
int GuitarPro5::readBeatEffects(int track, Segment* segment)
{
int effects = 0;
uchar fxBits1 = readUChar();
uchar fxBits2 = readUChar();
if (fxBits1 & 0x20) {
effects = readUChar();
// 1 - tapping
// 2 - slapping
// 3 - popping
}
if (fxBits2 & 0x04)
readTremoloBar(track, segment); // readBend();
if (fxBits1 & 0x40) {
int a = readChar(); // down stroke length
int b = readChar(); // up stroke length
qDebug(" 0x40: 0x%02x 0x%02x\n", a, b);
}
if (fxBits2 & 0x02) {
int a = readChar(); // stroke pick direction
qDebug(" 0x02: 0x%02x\n", a);
}
return effects;
}
//---------------------------------------------------------
// readPageSetup
//---------------------------------------------------------
void GuitarPro5::readPageSetup()
{
skip(version > 500 ? 49 : 30);
for (int i = 0; i < 11; ++i) {
skip(4);
readBytePascalString();
}
}
//---------------------------------------------------------
// readBeat
//---------------------------------------------------------
int GuitarPro5::readBeat(int tick, int voice, Measure* measure, int staffIdx, Tuplet** tuplets)
{
uchar beatBits = readUChar();
bool dotted = beatBits & 0x1;
int pause = -1;
if (beatBits & 0x40)
pause = readUChar();
// readDuration
int len = readChar();
int tuple = 0;
if (beatBits & 0x20)
tuple = readInt();
Segment* segment = measure->getSegment(SegChordRest, tick);
if (beatBits & 0x2)
readChord(segment, staffIdx * VOICES);
Lyrics* lyrics = 0;
if (beatBits & 0x4) {
QString txt = readDelphiString();
lyrics = new Lyrics(score);
lyrics->setText(txt);
}
int beatEffects = 0;
if (beatBits & 0x8)
beatEffects = readBeatEffects(staffIdx * VOICES + voice, segment);
if (beatBits & 0x10)
readMixChange();
int strings = readUChar(); // used strings mask
Fraction l = len2fraction(len);
ChordRest* cr;
if (voice != 0 && pause == 0 && strings == 0)
cr = 0;
else {
if (strings == 0)
cr = new Rest(score);
else
cr = new Chord(score);
cr->setTrack(staffIdx * VOICES + voice);
if (tuple) {
Tuplet* tuplet = tuplets[staffIdx * 2 + voice];
if ((tuplet == 0) || (tuplet->elements().size() == tuple)) {
tuplet = new Tuplet(score);
// int track = staffIdx * 2 + voice;
tuplets[staffIdx * 2 + voice] = tuplet;
tuplet->setTrack(cr->track());
tuplet->setParent(measure);
}
tuplet->setTrack(cr->track());
tuplet->setBaseLen(l);
setTuplet(tuplet, tuple);
cr->setTuplet(tuplet);
tuplet->add(cr);
}
TDuration d(l);
d.setDots(dotted ? 1 : 0);
if (dotted)
l = l + (l/2);
cr->setDuration(l);
if (cr->type() == REST && pause == 0)
cr->setDurationType(TDuration::V_MEASURE);
else
cr->setDurationType(d);
segment->add(cr);
Staff* staff = cr->staff();
int numStrings = staff->part()->instr()->tablature()->strings();
for (int i = 6; i >= 0; --i) {
if (strings & (1 << i) && ((6-i) < numStrings)) {
Note* note = new Note(score);
static_cast<Chord*>(cr)->add(note);
readNote(6-i, note);
note->setTpcFromPitch();
}
}
if (lyrics)
cr->add(lyrics);
}
int rr = readChar();
if (cr && (cr->type() == CHORD)) {
Chord* chord = static_cast<Chord*>(cr);
applyBeatEffects(chord, beatEffects);
if (rr == 0x2)
chord->setStemDirection(DOWN);
else if (rr == 0xa)
chord->setStemDirection(UP);
else
qDebug(" 1beat read 0x%02x\n", rr);
}
int r = readChar();
if (r & 0x8) {
int rrr = readChar();
qDebug(" 3beat read 0x%02x\n", rrr);
}
return cr ? cr->actualTicks() : measure->ticks();
}
//---------------------------------------------------------
// readMeasure
//---------------------------------------------------------
void GuitarPro5::readMeasure(Measure* measure, int staffIdx, Tuplet** tuplets)
{
for (int voice = 0; voice < 2; ++voice) {
int tick = measure->tick();
int beats = readInt();
for (int beat = 0; beat < beats; ++beat) {
tick += readBeat(tick, voice, measure, staffIdx, tuplets);
}
}
}
//---------------------------------------------------------
// readMixChange
//---------------------------------------------------------
void GuitarPro5::readMixChange()
{
/*char patch =*/ readChar();
skip(16);
char volume = readChar();
char pan = readChar();
char chorus = readChar();
char reverb = readChar();
char phase = readChar();
char tremolo = readChar();
readDelphiString(); // tempo name
int tempo = readInt();
if (volume >= 0)
readChar();
if (pan >= 0)
readChar();
if (chorus >= 0)
readChar();
if (reverb >= 0)
readChar();
if (phase >= 0)
readChar();
if (tremolo >= 0)
readChar();
if (tempo >= 0) {
readChar();
if (version > 500)
readChar();
}
readChar();
skip(1);
if (version > 500) {
readDelphiString();
readDelphiString();
}
}
//---------------------------------------------------------
// readChord
//---------------------------------------------------------
void GuitarPro5::readChord(Segment* seg, int track)
{
skip(17);
QString name = readPascalString(21);
skip(4);
/*int firstFret =*/ readInt();
for (int i = 0; i < 7; ++i) {
/*int fret =*/ readInt();
}
skip(32);
if (name.isEmpty())
return;
Harmony* harmony = new Harmony(seg->score());
harmony->setHarmony(name);
harmony->setTrack(track);
seg->add(harmony);
}
//---------------------------------------------------------
// readTracks
//---------------------------------------------------------
void GuitarPro5::readTracks()
{
for (int i = 0; i < staves; ++i) {
int tuning[GP_MAX_STRING_NUMBER];
Staff* staff = score->staff(i);
Part* part = staff->part();
uchar c = readUChar(); // simulations bitmask
if (c & 0x2) { // 12 stringed guitar
}
if (c & 0x4) { // banjo track
}
if (i == 0 || version == 500)
skip(1);
QString name = readPascalString(40);
int strings = readInt();
if (strings <= 0 || strings > GP_MAX_STRING_NUMBER)
throw GP_BAD_NUMBER_OF_STRINGS ;
for (int j = 0; j < strings; ++j) {
tuning[j] = readInt();
}
for (int j = strings; j < GP_MAX_STRING_NUMBER; ++j)
readInt();
/*int midiPort =*/ readInt(); // -1
int midiChannel = readInt() - 1;
/*int midiChannel2 =*/ readInt(); // -1
int frets = readInt();
int capo = readInt();
/*int color =*/ readInt();
skip(version > 500 ? 49 : 44);
if (version > 500) {
readDelphiString();
readDelphiString();
}
int tuning2[strings];
for (int k = 0; k < strings; ++k)
tuning2[strings-k-1] = tuning[k];
Tablature* tab = new Tablature(frets, strings, tuning2);
Instrument* instr = part->instr();
instr->setTablature(tab);
part->setPartName(name);
part->setLongName(name);
instr->setTranspose(Interval(capo));
//
// determine clef
//
int patch = channelDefaults[midiChannel].patch;
ClefType clefId = CLEF_G;
if (c & 0x1) {
clefId = CLEF_PERC;
instr->setUseDrumset(true);
staff->setStaffType(score->staffTypes().at(PERCUSSION_STAFF_TYPE));
}
else if (patch >= 24 && patch < 32)
clefId = CLEF_G3;
else if (patch >= 32 && patch < 40)
clefId = CLEF_F8;
Measure* measure = score->firstMeasure();
Clef* clef = new Clef(score);
clef->setClefType(clefId);
clef->setTrack(i * VOICES);
Segment* segment = measure->getSegment(SegClef, 0);
segment->add(clef);
Channel& ch = instr->channel(0);
if (c & 1) {
ch.program = 0;
ch.bank = 128;
}
else {
ch.program = patch;
ch.bank = 0;
}
ch.volume = channelDefaults[midiChannel].volume;
ch.pan = channelDefaults[midiChannel].pan;
ch.chorus = channelDefaults[midiChannel].chorus;
ch.reverb = channelDefaults[midiChannel].reverb;
// missing: phase, tremolo
ch.updateInitList();
}
skip(version == 500 ? 2 : 1);
}
//---------------------------------------------------------
// readMeasures
//---------------------------------------------------------
void GuitarPro5::readMeasures()
{
Measure* measure = score->firstMeasure();
for (int bar = 0; bar < measures; ++bar, measure = measure->nextMeasure()) {
const GpBar& gpbar = bars[bar];
if (!gpbar.marker.isEmpty()) {
Text* s = new RehearsalMark(score);
s->setText(gpbar.marker.trimmed());
s->setTrack(0);
Segment* segment = measure->getSegment(SegChordRest, measure->tick());
segment->add(s);
}
Tuplet* tuplets[staves * 2]; // two voices
for (int track = 0; track < staves*2; ++track)
tuplets[track] = 0;
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
readMeasure(measure, staffIdx, tuplets);
if (!(((bar == (measures-1)) && (staffIdx == (staves-1))))) {
int a = readChar();
qDebug(" ======skip %02x\n", a);
}
}
}
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
void GuitarPro5::read(QFile* fp)
{
f = fp;
readInfo();
readLyrics();
readPageSetup();
int tempo = readInt();
if (version > 500)
skip(1);
key = readInt();
/* int octave =*/ readChar(); // octave
readChannels();
skip(42);
measures = readInt();
staves = readInt();
int tnumerator = 4;
int tdenominator = 4;
for (int i = 0; i < measures; ++i) {
if (i > 0)
skip(1);
GpBar bar;
uchar barBits = readUChar();
if (barBits & 0x1)
tnumerator = readUChar();
if (barBits & 0x2)
tdenominator = readUChar();
if (barBits & 0x4)
bar.repeatFlags |= RepeatStart;
if (barBits & 0x8) { // number of repeats
bar.repeatFlags |= RepeatEnd;
bar.repeats = readUChar();
}
if (barBits & 0x20) {
bar.marker = readDelphiString(); // new section?
/*int color =*/ readInt(); // color?
}
if (barBits & 0x10) // alternative ending to
/*uchar c =*/ readUChar();
if (barBits & 0x40) {
bar.keysig = readUChar();
/*uchar c =*/ readUChar(); // minor
}
if (barBits & 0x80)
bar.barLine = DOUBLE_BAR;
if (barBits & 0x3)
skip(4);
if ((barBits & 0x10) == 0)
skip(1);
readChar(); // triple feel (none, 8, 16)
bar.timesig = Fraction(tnumerator, tdenominator);
bars.append(bar);
}
//
// create a part for every staff
//
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
Part* part = new Part(score);
Staff* s = new Staff(score, part, staffIdx);
part->insertStaff(s);
score->staves().push_back(s);
score->appendPart(part);
}
createMeasures();
readTracks();
readMeasures();
setTempo(tempo);
}
//---------------------------------------------------------
// importGTP
//---------------------------------------------------------
bool MuseScore::importGTP(Score* score, const QString& name)
{
if (name.isEmpty())
return false;
QFile fp(name);
if (!fp.open(QIODevice::ReadOnly))
return false;
uchar l;
fp.read((char*)&l, 1);
char ss[30];
fp.read(ss, 30);
ss[l] = 0;
QString s(ss);
if (s.startsWith("FICHIER GUITAR PRO "))
s = s.mid(20);
else if (s.startsWith("FICHIER GUITARE PRO "))
s = s.mid(21);
else {
qDebug("unknown gtp format <%s>\n", ss);
return false;
}
int a = s.left(1).toInt();
int b = s.mid(2).toInt();
int version = a * 100 + b;
GuitarPro* gp;
if (a == 1)
gp = new GuitarPro1(score, version);
if (a == 2)
gp = new GuitarPro2(score, version);
if (a == 3)
gp = new GuitarPro3(score, version);
else if (a == 4)
gp = new GuitarPro4(score, version);
else if (a == 5)
gp = new GuitarPro5(score, version);
else {
qDebug("unknown gtp format %d\n", version);
return false;
}
try {
gp->read(&fp);
}
catch(GuitarPro::GuitarProError errNo) {
QMessageBox::warning(0,
QWidget::tr("MuseScore: Import GuitarPro"),
QString("Load failed: ") + gp->error(errNo),
QString::null, QWidget::tr("Quit"), QString::null, 0, 1);
fp.close();
qDebug("guitar pro import error====\n");
// avoid another error message box
return true;
}
fp.close();
MeasureBase* m;
if (!score->measures()->first()) {
m = new VBox(score);
m->setTick(0);
score->addMeasure(m, 0);
}
else {
m = score->measures()->first();
if (m->type() != VBOX) {
MeasureBase* mb = new VBox(score);
mb->setTick(0);
score->addMeasure(mb, m);
m = mb;
}
}
if (!gp->title.isEmpty()) {
Text* s = new Text(score);
// s->setSubtype(TEXT_TITLE);
s->setTextStyleType(TEXT_STYLE_TITLE);
s->setText(gp->title);
m->add(s);
}
if (!gp->subtitle.isEmpty() && !gp->artist.isEmpty() && !gp->album.isEmpty()) {
Text* s = new Text(score);
// s->setSubtype(TEXT_SUBTITLE);
s->setTextStyleType(TEXT_STYLE_SUBTITLE);
QString str;
if (!gp->subtitle.isEmpty())
str.append(gp->subtitle);
if (!gp->artist.isEmpty()) {
if (!str.isEmpty())
str.append("\n");
str.append(gp->artist);
}
if (!gp->album.isEmpty()) {
if (!str.isEmpty())
str.append("\n");
str.append(gp->album);
}
s->setText(str);
m->add(s);
}
if (!gp->composer.isEmpty()) {
Text* s = new Text(score);
// s->setSubtype(TEXT_COMPOSER);
s->setTextStyleType(TEXT_STYLE_COMPOSER);
s->setText(gp->composer);
m->add(s);
}
int idx = 0;
for (Measure* m = score->firstMeasure(); m; m = m->nextMeasure(), ++idx) {
const GpBar& bar = gp->bars[idx];
if (bar.barLine != NORMAL_BAR)
m->setEndBarLineType(bar.barLine, false);
}
score->lastMeasure()->setEndBarLineType(END_BAR, false);
//
// create parts (excerpts)
//
foreach(Part* part, score->parts()) {
Score* pscore = new Score(score);
pscore->syntiState().append(SyntiParameter("soundfont", MScore::soundFont));
pscore->style()->set(ST_createMultiMeasureRests, true);
QList<int> stavesMap;
Part* p = new Part(pscore);
p->setInstrument(*part->instr());
Staff* staff = part->staves()->front();
Staff* s = new Staff(pscore, p, 0);
s->setUpdateKeymap(true);
StaffType* st = staff->staffType();
s->setStaffType(st);
int idx = pscore->staffTypes().indexOf(st);
if (idx == -1)
pscore->staffTypes().append(st);
s->linkTo(staff);
p->staves()->append(s);
pscore->staves().append(s);
stavesMap.append(score->staffIdx(staff));
if (part->staves()->front()->staffType()->group() == PITCHED_STAFF) {
s = new Staff(pscore, p, 1);
s->setUpdateKeymap(true);
StaffTypeTablature* st = static_cast<StaffTypeTablature*>(pscore->staffTypes().at(TAB_STAFF_TYPE));
st->setSlashStyle(true);
s->setStaffType(st);
s->linkTo(staff);
p->staves()->append(s);
pscore->staves().append(s);
stavesMap.append(score->staffIdx(staff));
p->staves()->front()->addBracket(BracketItem(BRACKET_NORMAL, 2));
}
pscore->appendPart(p);
cloneStaves(score, pscore, stavesMap);
pscore->setName(part->partName());
Excerpt* excerpt = new Excerpt(pscore);
excerpt->setTitle(part->partName());
excerpt->parts().append(part);
score->excerpts().append(excerpt);
if (part->staves()->front()->staffType()->group() == PITCHED_STAFF) {
Staff* staff2 = pscore->staff(1);
staff2->setStaffType(pscore->staffTypes().at(TAB_STAFF_TYPE));
}
//
// create excerpt title
//
MeasureBase* measure = pscore->first();
if (!measure || (measure->type() != VBOX)) {
MeasureBase* mb = new VBox(pscore);
mb->setTick(0);
pscore->addMeasure(mb, measure);
measure = mb;
}
Text* txt = new Text(pscore);
txt->setTextStyleType(TEXT_STYLE_INSTRUMENT_EXCERPT);
txt->setText(part->longName().toPlainText());
measure->add(txt);
//
// layout score
//
pscore->setPlaylistDirty(true);
pscore->rebuildMidiMapping();
pscore->updateChannel();
pscore->updateNotes();
pscore->setLayoutAll(true);
pscore->addLayoutFlags(LAYOUT_FIX_TICKS | LAYOUT_FIX_PITCH_VELO);
pscore->doLayout();
}
// album
// copyright
score->setSaved(false);
score->setCreated(true);
delete gp;
score->rebuildMidiMapping();
return true;
}