Support for fret diagrams in the GPX format

This commit is contained in:
John Pirie 2014-06-13 10:36:57 +01:00
parent 3fce939333
commit 539d11edb5
5 changed files with 184 additions and 194 deletions

View file

@ -651,7 +651,18 @@ void GuitarPro1::read(QFile* fp)
Segment* segment = measure->getSegment(SegmentType::ChordRest, tick);
if (beatBits & 0x2) {
int numStrings = score->staff(staffIdx)->part()->instr()->stringData()->strings();
readChord(segment, staffIdx * VOICES, numStrings);
int header = readUChar();
QString name;
if ((header & 1) == 0) {
name = readDelphiString();
readChord(segment, staffIdx * VOICES, numStrings, name, false);
}
else {
skip(25);
name = readPascalString(34);
readChord(segment, staffIdx * VOICES, numStrings, name, true);
skip(36);
}
}
Lyrics* lyrics = 0;
if (beatBits & 0x4) {
@ -731,6 +742,46 @@ void GuitarPro::setTempo(int tempo, Measure* measure)
score->setTempo(measure->tick(), tt->tempo());
}
//---------------------------------------------------------
// readChord
//---------------------------------------------------------
void GuitarPro::readChord(Segment* seg, int track, int numStrings, QString name, bool gpHeader)
{
FretDiagram* fret = new FretDiagram(score);
fret->setTrack(track);
fret->setStrings(numStrings);
int firstFret = readInt();
fret->setOffset(firstFret-1);
if (firstFret != 0 || gpHeader) {
for (int i = 0; i < (gpHeader ? 7 : 6); ++i) {
int currentFret = readInt();
// read the frets and add them to the fretboard
// substract 1 extra from numStrings as we count from 0
if (i > numStrings - 1) {}
else if (currentFret > 0) {
fret->setDot(numStrings - 1 - i, currentFret-firstFret+1);
}
else if (currentFret == 0) {
fret->setDot(numStrings - 1 - i, 0);
fret->setMarker(numStrings - 1 - i, '0');
}
else if (currentFret == -1) {
fret->setDot(numStrings - 1 - i, 0);
fret->setMarker(numStrings - 1 - i, 'X');
}
}
}
seg->add(fret);
if (name.isEmpty())
return;
Harmony* harmony = new Harmony(seg->score());
harmony->setHarmony(name);
harmony->setTrack(track);
seg->add(harmony);
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
@ -948,7 +999,18 @@ qDebug("BeginRepeat=============================================");
Segment* segment = measure->getSegment(SegmentType::ChordRest, tick);
if (beatBits & 0x2) {
int numStrings = score->staff(staffIdx)->part()->instr()->stringData()->strings();
readChord(segment, staffIdx * VOICES, numStrings);
int header = readUChar();
QString name;
if ((header & 1) == 0) {
name = readDelphiString();
readChord(segment, staffIdx * VOICES, numStrings, name, false);
}
else {
skip(25);
name = readPascalString(34);
readChord(segment, staffIdx * VOICES, numStrings, name, true);
skip(36);
}
}
Lyrics* lyrics = 0;
if (beatBits & 0x4) {
@ -1262,77 +1324,6 @@ int GuitarPro1::readBeatEffects(int, Segment*)
return 0;
}
//---------------------------------------------------------
// readChord
//---------------------------------------------------------
void GuitarPro1::readChord(Segment* seg, int track, int numStrings)
{
FretDiagram* fret = new FretDiagram(score);
fret->setTrack(track);
fret->setStrings(numStrings);
int header = readUChar();
QString name;
if ((header & 1) == 0) {
name = readDelphiString();
int firstFret = readInt();
fret->setOffset(firstFret-1);
if (firstFret) {
for (int i = 0; i < 6; ++i) {
int currentFret = readInt();
// read the frets and add them to the fretboard
// substract 1 extra from numStrings as we count from 0
if (i > numStrings-1) {}
else if (currentFret > 0) {
fret->setDot(numStrings-1-i, currentFret-firstFret+1);
}
else if (currentFret == 0) {
fret->setDot(numStrings-1-i, 0);
fret->setMarker(numStrings-1-i, '0');
}
else if (currentFret == -1) {
fret->setDot(numStrings-1-i, 0);
fret->setMarker(numStrings-1-i, 'X');
}
}
}
}
else {
skip(25);
name = readPascalString(34);
int firstFret = readInt();
fret->setOffset(firstFret-1);
// even if the guitar has 6 (or fewer) strings we must read 7 digits
for (int i = 0; i < 7; ++i) {
int currentFret = readInt();
// read the frets and add them to the fretboard
// substract 1 extra from numStrings as we count from 0
if (i > numStrings-1) {}
else if (currentFret > 0) {
fret->setDot(numStrings-1-i, currentFret-firstFret+1);
}
else if (currentFret == 0) {
fret->setDot(numStrings-1-i, 0);
fret->setMarker(numStrings-1-i, '0');
}
else if (currentFret == -1) {
fret->setDot(numStrings-1-i, 0);
fret->setMarker(numStrings-1-i, 'X');
}
}
skip(36);
}
seg->add(fret);
if (name.isEmpty())
return;
Harmony* harmony = new Harmony(seg->score());
harmony->setHarmony(name);
harmony->setTrack(track);
seg->add(harmony);
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
@ -1588,7 +1579,18 @@ void GuitarPro3::read(QFile* fp)
Segment* segment = measure->getSegment(SegmentType::ChordRest, tick);
if (beatBits & 0x2) {
int numStrings = score->staff(staffIdx)->part()->instr()->stringData()->strings();
readChord(segment, staffIdx * VOICES, numStrings);
int header = readUChar();
QString name;
if ((header & 1) == 0) {
name = readDelphiString();
readChord(segment, staffIdx * VOICES, numStrings, name, false);
}
else {
skip(25);
name = readPascalString(34);
readChord(segment, staffIdx * VOICES, numStrings, name, true);
skip(36);
}
}
Lyrics* lyrics = 0;
if (beatBits & 0x4) {
@ -2071,78 +2073,6 @@ void GuitarPro4::readInfo()
comments.append(readDelphiString());
}
//---------------------------------------------------------
// readChord
//---------------------------------------------------------
void GuitarPro4::readChord(Segment* seg, int track, int numStrings)
{
FretDiagram* fret = new FretDiagram(score);
fret->setTrack(track);
fret->setStrings(numStrings);
int header = readUChar();
QString name;
if ((header & 1) == 0) {
name = readDelphiString();
int firstFret = readInt();
fret->setOffset(firstFret-1);
if (firstFret != 0) {
for (int i = 0; i < 6; ++i) {
int currentFret = readInt();
// read the frets and add them to the fretboard
// substract 1 extra from numStrings as we count from 0
if (i > numStrings-1) {}
else if (currentFret > 0) {
fret->setDot(numStrings-1-i, currentFret-firstFret+1);
}
else if (currentFret == 0) {
fret->setDot(numStrings-1-i, 0);
fret->setMarker(numStrings-1-i, '0');
}
else if (currentFret == -1) {
fret->setDot(numStrings-1-i, 0);
fret->setMarker(numStrings-1-i, 'X');
}
}
}
}
else {
skip(16);
name = readPascalString(21);
skip(4);
int firstFret = readInt();
fret->setOffset(firstFret-1);
// even if the guitar has 6 (or fewer) strings we must read 7 digits
for (int i = 0; i < 7; ++i) {
int currentFret = readInt();
// read the frets and add them to the fretboard
// substract 1 extra from numStrings as we count from 0
if (i > numStrings-1) {}
else if (currentFret > 0) {
fret->setDot(numStrings-1-i, currentFret-firstFret+1);
}
else if (currentFret == 0) {
fret->setDot(numStrings-1-i, 0);
fret->setMarker(numStrings-1-i, '0');
}
else if (currentFret == -1) {
fret->setDot(numStrings-1-i, 0);
fret->setMarker(numStrings-1-i, 'X');
}
}
skip(32);
}
seg->add(fret);
if (name.isEmpty())
return;
Harmony* harmony = new Harmony(seg->score());
harmony->setHarmony(name);
harmony->setTrack(track);
seg->add(harmony);
}
//---------------------------------------------------------
// read
@ -2331,7 +2261,19 @@ void GuitarPro4::read(QFile* fp)
Segment* segment = measure->getSegment(SegmentType::ChordRest, tick);
if (beatBits & 0x2){
int numStrings = score->staff(staffIdx)->part()->instr()->stringData()->strings();
readChord(segment, staffIdx * VOICES, numStrings);
int header = readUChar();
QString name;
if ((header & 1) == 0) {
name = readDelphiString();
readChord(segment, staffIdx * VOICES, numStrings, name, false);
}
else {
skip(16);
name = readPascalString(21);
skip(4);
readChord(segment, staffIdx * VOICES, numStrings, name, true);
skip(32);
}
}
Lyrics* lyrics = 0;
if (beatBits & 0x4) {
@ -2870,7 +2812,12 @@ int GuitarPro5::readBeat(int tick, int voice, Measure* measure, int staffIdx, Tu
Segment* segment = measure->getSegment(SegmentType::ChordRest, tick);
if (beatBits & 0x2) {
int numStrings = score->staff(staffIdx)->part()->instr()->stringData()->strings();
readChord(segment, staffIdx * VOICES, numStrings);
skip(17);
QString name = readPascalString(21);
skip(4);
// no header to be read in the GP5 format - default to true.
readChord(segment, staffIdx * VOICES, numStrings, name, true);
skip(32);
}
Lyrics* lyrics = 0;
if (beatBits & 0x4) {
@ -3035,48 +2982,6 @@ void GuitarPro5::readMixChange(Measure* measure)
}
}
//---------------------------------------------------------
// readChord
//---------------------------------------------------------
void GuitarPro5::readChord(Segment* seg, int track, int numStrings)
{
FretDiagram* fret = new FretDiagram(score);
fret->setTrack(track);
fret->setStrings(numStrings);
skip(17);
QString name = readPascalString(21);
skip(4);
int firstFret = readInt();
fret->setOffset(firstFret-1);
// even if the guitar has 6 (or fewer) strings we must read 7 digits
for (int i = 0; i < 7; ++i) {
int currentFret = readInt();
// read the frets and add them to the fretboard
// substract 1 extra from numStrings as we count from 0
if (i > numStrings-1) {}
else if (currentFret > 0) {
fret->setDot(numStrings-1-i, currentFret-firstFret+1);
}
else if (currentFret == 0) {
fret->setDot(numStrings-1-i, 0);
fret->setMarker(numStrings-1-i, '0');
}
else if (currentFret == -1) {
fret->setDot(numStrings-1-i, 0);
fret->setMarker(numStrings-1-i, 'X');
}
}
skip(32);
seg->add(fret);
if (name.isEmpty())
return;
Harmony* harmony = new Harmony(seg->score());
harmony->setHarmony(name);
harmony->setTrack(track);
seg->add(harmony);
}
//---------------------------------------------------------
// readTracks
@ -3466,6 +3371,10 @@ void GuitarPro6::parseFile(char* filename, QByteArray* data)
{
// test to check if we are dealing with the score
if (!strcmp(filename, "score.gpif")) {
QFile file("/tmp/score.gpif");
file.open(QIODevice::WriteOnly);
file.write(*data);
file.close();
readGpif(data);
}
}
@ -3532,6 +3441,69 @@ void GuitarPro6::readMasterTracks(QDomNode* masterTrack)
}
}
//---------------------------------------------------------
// readChord
//---------------------------------------------------------
void GuitarPro6::readChord(QDomNode* diagram, int track)
{
// initialise a new fret diagram for our current track
FretDiagram* fretDiagram = new FretDiagram(score);
fretDiagram->setTrack(track);
// get the identifier to set as the domain in the map
int id = diagram->attributes().namedItem("id").toAttr().value().toInt();
QDomNode diagramNode = diagram->firstChild();
// set the number of strings on this part
int stringCount = diagramNode.attributes().namedItem("stringCount").toAttr().value().toInt();
fretDiagram->setStrings(stringCount);
// set the fret offset
int baseFret = diagramNode.attributes().namedItem("baseFret").toAttr().value().toInt();
fretDiagram->setOffset(baseFret);
QDomNode diagramEntity = diagramNode.firstChild();
int counter = 0;
while (!diagramEntity.isNull()) {
QString nodeName = diagramEntity.nodeName();
// new fret
if (!nodeName.compare("Fret")) {
// get the string and fret numbers from the arguments to the node as integers
int string = diagramEntity.attributes().namedItem("string").toAttr().value().toInt();
int fret = diagramEntity.attributes().namedItem("fret").toAttr().value().toInt();
// if there are unspecified string values, add the X marker to that string
while (counter < string) {
fretDiagram->setMarker(counter, 'X');
counter++;
}
// look at the specified string/fret and add to diagram
if (fret == 0) {
fretDiagram->setMarker(string, '0');
counter++;
}
else {
qDebug("Setting fret (string=%d,fret=%d)", string, fret-baseFret);
fretDiagram->setDot(string, fret);
counter++;
}
}
// move to the next string/fret specification
diagramEntity = diagramEntity.nextSibling();
}
// mark any missing strings as 'X'
while (counter < stringCount) {
fretDiagram->setMarker(counter, 'X');
counter++;
}
// insert the fret diagram into the map of diagrams
fretDiagrams.insert(id, fretDiagram);
}
//---------------------------------------------------------
// readTracks
//---------------------------------------------------------
@ -3553,7 +3525,8 @@ void GuitarPro6::readTracks(QDomNode* track)
else if (nodeName == "Properties") {
QDomNode currentProperty = currentNode.firstChild();
while (!currentProperty.isNull()) {
if (currentProperty.attributes().namedItem("name").toAttr().value() == "Tuning") {
QString propertyName = currentProperty.attributes().namedItem("name").toAttr().value();
if (!propertyName.compare("Tuning")) {
// set up the tuning for the part
QString tuningString = currentProperty.firstChild().toElement().text();
QStringList tuningStringList = tuningString.split(" ");
@ -3569,6 +3542,14 @@ void GuitarPro6::readTracks(QDomNode* track)
Instrument* instr = part->instr();
instr->setStringData(*stringData);
}
else if (!propertyName.compare("DiagramCollection")) {
QDomNode items = currentProperty.firstChild();
QDomNode currentItem = items.firstChild();
while (!currentItem.isNull()) {
readChord(&currentItem, trackCounter);
currentItem = currentItem.nextSibling();
}
}
else
unhandledNode(nodeName);
currentProperty = currentProperty.nextSibling();
@ -3845,6 +3826,10 @@ void GuitarPro6::readMasterBars(GPPartInfo* partInfo)
}
}
}
else if (!currentNode.nodeName().compare("Chord")) {
int key = currentNode.toElement().text().toInt();
segment->add(fretDiagrams[key]);
}
else if (currentNode.nodeName() == "Rhythm") {
// we have found a rhythm
QString refString = currentNode.attributes().namedItem("ref").toAttr().value();

View file

@ -23,6 +23,7 @@
#include "libmscore/mscore.h"
#include "libmscore/fraction.h"
#include "libmscore/fret.h"
namespace Ms {
@ -111,6 +112,7 @@ class GuitarPro {
void createMeasures();
void applyBeatEffects(Chord*, int beatEffects);
void readTremoloBar(int track, Segment*);
void readChord(Segment* seg, int track, int numStrings, QString name, bool gpHeader);
public:
QString title, subtitle, artist, album, composer;
@ -138,7 +140,6 @@ class GuitarPro {
class GuitarPro1 : public GuitarPro {
protected:
virtual void readChord(Segment*, int track, int numStrings);
void readNote(int string, Note* note);
virtual int readBeatEffects(int track, Segment*);
@ -178,7 +179,6 @@ class GuitarPro4 : public GuitarPro {
void readInfo();
void readNote(int string, Note* note, GpNote*);
virtual void readChord(Segment*, int track, int numStrings);
virtual int readBeatEffects(int track, Segment* segment);
virtual void readMixChange(Measure* measure);
@ -198,7 +198,6 @@ class GuitarPro5 : public GuitarPro {
virtual int readBeatEffects(int track, Segment* segment);
void readNote(int string, Note* note);
virtual void readMixChange(Measure* measure);
virtual void readChord(Segment*, int track, int numStrings);
void readMeasure(Measure* measure, int staffIdx, Tuplet*[]);
void readArtificialHarmonic();
void readTracks();
@ -235,6 +234,8 @@ class GuitarPro6 : public GuitarPro {
QDomNode notes;
QDomNode rhythms;
};
// a mapping from identifiers to fret diagrams
QMap<int, FretDiagram*> fretDiagrams;
void parseFile(char* filename, QByteArray* data);
int readBit();
QByteArray getBytes(QByteArray* buffer, int offset, int length);
@ -245,6 +246,7 @@ class GuitarPro6 : public GuitarPro {
int readBitsReversed(int bitsToRead);
void readGpif(QByteArray* data);
void readScore(QDomNode* metadata);
void readChord(QDomNode* diagram, int track);
int findNumMeasures(GPPartInfo* partInfo);
void readMasterTracks(QDomNode* masterTrack);
void readTracks(QDomNode* tracks);

Binary file not shown.

View file

@ -61,6 +61,7 @@ private slots:
void gpDottedTuplets() { gpReadTest("dotted-tuplets", "gp5"); }
void gpTupletSlur() { gpReadTest("tuplet-with-slur", "gp4"); }
void gpBeamsStemsLL() { gpReadTest("beams-stems-ledger-lines", "gp5"); }
void gpxFretDiagram() { gpReadTest("fret-diagram", "gpx"); }
void gp5FretDiagram() { gpReadTest("fret-diagram", "gp5"); }
void gp4FretDiagram() { gpReadTest("fret-diagram", "gp4"); }
};

View file

@ -30,5 +30,7 @@ cp $MSCORE/keysig.gp4.mscx keysig.gp4-ref.mscx
cp $MSCORE/dotted-tuplets.gp5.mscx dotted-tuplets.gp5-ref.mscx
cp $MSCORE/tuplet-with-slur.gp4.mscx tuplet-with-slur.gp4-ref.mscx
cp $MSCORE/beams-stems-ledger-lines.gp5.mscx beams-stems-ledger-lines.gp5-ref.mscx
cp $MSCORE/fret-diagram.gpx.mscx fret-diagram.gpx-ref.mscx
cp $MSCORE/fret-diagram.gp5.mscx fret-diagram.gp5-ref.mscx
cp $MSCORE/fret-diagram.gp4.mscx fret-diagram.gp4-ref.mscx