MuseScore/mscore/importptb.cpp
ws ec3be9a99a Replacd integer midi tick values by fractions.
- tick names a position on the time axis
- tick is always a Fraction()
- only Measure() and Segment() (and Tuplet?) have a tick value
- tick() for an generic element return only a sensible value if isMeasure() or isSegment() or isSegment(parent())

- "ticks" names a duration stored in a Fraction()
- the tick value for an Segment is relative to its measure

- rename "duration" to "ticks"
- rename afrac() to tick()
- rename rfrac() to rtick()
- rename some variables, changing "fraction" into "tick"
  (example: actualFraction() into actualTicks())

- Lyrics ticks are written as Fraction, on read if xmlreader sees a "/" it reads a fraction
  else midi ticks for backwards compatibility
2019-02-18 11:46:05 +01:00

1353 lines
44 KiB
C++

#include "importptb.h"
#include "assert.h"
#include <libmscore/part.h>
#include <libmscore/staff.h>
#include <libmscore/measure.h>
#include <libmscore/symbol.h>
#include <libmscore/tie.h>
#include <libmscore/bend.h>
#include <libmscore/timesig.h>
#include <libmscore/sym.h>
#include <libmscore/articulation.h>
#include <libmscore/tuplet.h>
#include <libmscore/instrument.h>
#include <libmscore/clef.h>
#include <libmscore/rest.h>
#include <libmscore/stafftext.h>
#include <libmscore/chord.h>
#include <libmscore/tempotext.h>
#include <libmscore/excerpt.h>
#include <libmscore/rehearsalmark.h>
#include <libmscore/bracketItem.h>
#include <libmscore/box.h>
#include <libmscore/palmmute.h>
namespace Ms {
bool PowerTab::readBoolean()
{
return readUChar() != 0;
}
unsigned char PowerTab::readUChar()
{
unsigned char byte;
_file->read((char*)&byte, 1);
return byte;
}
unsigned short PowerTab::readShort()
{
uint16_t val;
_file->read((char*)&val, 2);
return val;
}
char PowerTab::readChar()
{
char byte;
_file->read(&byte, 1);
return byte;
}
int PowerTab::readInt()
{
int32_t val;
_file->read((char*)&val, 4);
return val;
}
std::string PowerTab::readString(int length)
{
if (length == -1) {
length = readUChar();
if (length == 0xFF)
length = readShort();
}
char* p = new char[length];
_file->read(p, length);
std::string s(p, length);
delete[] p;
return s;
}
bool PowerTab::readVersion()
{
std::string version = readString(4);
version += std::string("-") + to_string(readShort());
return version == "ptab-4";
}
void PowerTab::skip(int len /* = 1 */)
{
for (int i = 0; i < len; ++i)
readChar();
}
void PowerTab::readSongInfo(ptSongInfo& info)
{
auto classification = readChar();
info.classification = classification;
if (classification == 0) {
skip(1);
info.name = readString();
info.interpret = readString();
auto releaseType = readChar();
switch (releaseType) {
case 0: {
/*auto albumType =*/ readChar();
info.album = readString();
info.year = readShort();
info.liverecording = readChar() != 0;
break;
}
case 1: {
info.album = readString();
info.liverecording = readChar() != 0;
break;
}
case 2: {
info.album = readString();
info.day = readShort();
info.month = readShort();
info.year = readShort();
break;
}
default:
assert(0);
}
if (readChar() == 0) {
info.author = readString();
info.lyricist = readString();
}
info.arrenger = readString();
info.guitarTranscriber = readString();
info.bassTranscriber = readString();
info.copyright = readString();
info.lyrics = readString();
info.guitarInstructions = readString();
info.bassInstructions = readString();
}
else if (classification == 1) {
info.name = readString();
info.album = readString();
info.style = readShort();
info.level = readUChar();
info.author = readString();
info.instructions = readString();
info.copyright = readString();
}
}
int PowerTab::readHeaderItems()
{
int itemCount = readShort();
if (itemCount != 0) {
int header = readShort();
if (header == 0xFFFF) {
if (readShort() != 1) {
return -1;
}
auto str = readString(readShort()); //section title
}
}
return itemCount;
}
void PowerTab::readTrackInfo(ptTrack& info)
{
TrackInfo tr;
tr.number = readUChar();
tr.name = readString();
tr.instrument = readUChar();
tr.volume = readUChar();
tr.balance = readUChar();
tr.reverb = readUChar();
tr.chorus = readUChar();
tr.tremolo = readUChar();
tr.phaser = readUChar();
tr.capo = readUChar();
tr.tuningName = readString();
tr.offset = readUChar();
int ln = readUChar();
for (int i = 0; i < ln; ++i)
tr.strings.push_back(readUChar());
info.infos.push_back(tr);
}
void PowerTab::readChord(ptTrack& info)
{
ptChord ch;
ch.key = readShort(); //chord key
ch.formula = readUChar();
ch.modification = readShort(); //Chord Modification
ch.extra = readUChar();
ch.top_fret = readUChar();
auto stringCount = readUChar();
for (int i = 0; i < stringCount; ++i) {
ch.frets.push_back(readUChar()); // fret
}
if (info.diagramMap.find({ {ch.key, ch.formula, ch.modification} }) == info.diagramMap.end())
info.diagramMap[ { {ch.key, ch.formula, ch.modification} }] = ch;
else {
auto a1 = info.diagramMap[ { {ch.key, ch.formula, ch.modification} }];
auto a2 = ch;
//?? int k = 1;
}
}
void PowerTab::readFontSettings()
{
readString(); //font name
readInt(); // point size
readInt(); // weight
readBoolean(); //italic
readBoolean(); //underline
readBoolean(); //strikeout
readInt(); //color
}
void PowerTab::readFloatingText()
{
readString(); //text
//rect :
readInt(); // left
readInt(); // top
readInt(); // right
readInt(); // bottom
readUChar();
readFontSettings();
}
void PowerTab::readDynamic()
{
readShort();
readUChar();
readUChar();
readShort();
}
void PowerTab::readKeySignature()
{
readUChar();
}
void PowerTab::readRehearsalSign(ptSection& sec)
{
auto c = readChar();
auto str = readString();
if (str.size()) {
sec.partName = str;
sec.partMarker = c;
}
}
void PowerTab::readChordText(ptSection& sec)
{
ptChordText cht;
cht.position = readUChar();
cht.key = readShort();
cht.formula = readUChar();
cht.formula_mod = readShort();
cht.extra = readUChar();
//sec.chordTextMap.push_back(cht);
sec.chordTextMap.insert({ cht.position, cht });
}
void PowerTab::readRhytmSlash(ptSection& sec)
{
stRhytmSlash rs;
rs.position = readUChar();
auto beaming = readUChar();
auto data = readInt();
auto duration = (data & 0xE00000) >> 21;
switch (duration) {
case 0:
rs.duration = 1;
break;
case 1:
rs.duration = 2;
break;
case 2:
rs.duration = 4;
break;
case 3:
rs.duration = 8;
break;
case 4:
rs.duration = 16;
}
rs.triplet = beaming & (0x20 | 0x40);
rs.tripletend = beaming & 0x80;
rs.dotted = data & 0x01;
rs.doubleDotted = data & 0x02;
rs.is_rest = data & 0x04;
sec.rhytm.emplace_back(rs);
}
void PowerTab::readGuitarIn(ptTrack& info)
{
ptGuitarIn gin;
gin.section = readShort();
gin.staff = readUChar() + staffInc;
gin.position = readUChar();
gin.rhytmSlash = readUChar();
gin.trackinfo = readUChar();
info.guitar_ins.push_back(gin);
//info.getSection(section).getPosition(position).addComponent(new ptGuitarIn(staff, inf));
}
void PowerTab::readTempoMarker(ptTrack& info)
{
auto section = readShort();
/*auto position =*/ readUChar();
auto tempo = readShort();
/*auto data =*/ readShort();
readString(); //description
#if 0 // TODO-ws
int tripletFeel = 0;
if (data & 0x01) {
tripletFeel = 8;
}
else if (data & 0x02) {
tripletFeel = 16;
}
#endif
if (tempo > 0) {
info.getSection(section).tempo = tempo;//.getPosition(position).addComponent(new ptTempo(tempo));
}
}
void PowerTab::readSectionSymbol(ptTrack& info)
{
int section = readShort();
int position = readUChar();
int data = readInt();
int endNumber = data >> 16;
info.getSection(section).getPosition(position).addComponent(new ptSymbol(endNumber));
}
void PowerTab::readTimeSignature(ptBar* bar)
{
skip(3);
int data = readUChar();
readUChar(); // measure pulses
bar->numerator = ((data - (data % 8)) / 8) + 1;
bar->denominator = pow(2, data % 8);
}
void PowerTab::readBarLine(ptSection& sec)
{
auto bar = new ptBar();
/*int position =*/ readUChar();
auto b_type = readUChar();
bar->repeatStart = (b_type >> 5) == 3;
bar->repeatClose = (b_type >> 5) == 4 ? b_type - 128 : 0;
bar->measureNo = sec.number;
readKeySignature();
readTimeSignature(bar);
readRehearsalSign(sec);
//sec.getPosition(position).addComponent(bar);
sec.bars.push_back(shared_ptr<ptBar>(bar));
/*if (bars.empty() || ( bars.back()->measureNo < bar->measureNo ))
bars.push_back(bar);*/
}
void PowerTab::readStaff(int staff, ptSection& sec)
{
skip(5);
for (int voice = 0; voice < 2; ++voice) {
int itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readPosition(staff, voice, sec);
if (i < itemCount - 1) {
readShort();
}
}
}
}
void PowerTab::readNote(ptBeat* beat)
{
ptNote note;
auto position = readUChar();
auto simpleData = readShort();
auto symboCount = readUChar();
for (int i = 0; i < symboCount; ++i) {
skip(2);
auto data3 = readUChar();
auto data4 = readUChar();
note.bend = data4 == 101 ? data3 / 16 + 1 : 0;
note.slide = data4 == 100 ? data3 + 1 : 0;
}
note.value = position & 0x1F;
note.str = ((position & 0xE0) >> 5);
note.tied = simpleData & 0x01;
note.dead = simpleData & 0x02;
note.hammer = simpleData & 0x08;
beat->notes.emplace_back(note);
}
void PowerTab::readPosition(int staff, int voice, ptSection& sec)
{
auto position = readUChar();
ptBeat* beat{ nullptr };
bool add = false;
if (voice == 0 || sec.beats[staff].empty()) {
beat = new ptBeat(staff, voice);
beat->position = position;
add = true;
}
else {
auto pos = sec.beats[staff].begin();
auto end = sec.beats[staff].end();
while (pos != end && pos->get()->position < position) {
++pos;
}
if (pos == end) {
beat = new ptBeat(staff, voice);
beat->position = position;
add = true;
}
else if (pos->get()->position == position) {
beat = pos->get();
}
else {
beat = new ptBeat(staff, voice);
beat->position = position;
sec.beats[staff].insert(pos, shared_ptr<ptBeat>(beat));
}
}
auto beaming = readUChar();
beaming = (((int)beaming - 128 < 0) ? beaming : beaming - 128);
readUChar();
auto data1 = readUChar();
auto data2 = readUChar(); //32 - palm mute, 4 - accent, 2 - staccato
auto data3 = readUChar();
auto durationValue = readUChar();
int multiBarRest = 1;
auto complexCount = readUChar();
for (int i = 0; i < complexCount; ++i) {
auto count = readShort();
readUChar();
auto type = readUChar();
if (type & 0x08) {
multiBarRest = count;
}
}
auto itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readNote(beat);
if ( i < itemCount - 1) {
readShort();
}
}
curTrack->infos[staff].notes_count += itemCount;
beat->mmrest = (itemCount == 0) ? multiBarRest : 1;
beat->vibrato = (( (data1 & 0x08) != 0) || ( (data1 & 0x10) != 0 ));
beat->grace = (data3 & 0x01) != 0;
beat->tuplet = (data3 & 0x20) != 0;
if (beat->duration != 0) {
durationValue = std::max((int)durationValue, beat->duration);
}
beat->duration = durationValue;//beat->duration == 0 ? durationValue : std::min(beat->duration, (int)durationValue);
beat->dotted = (data1 & 0x01);
beat->doubleDotted = (data1 & 0x02);
beat->arpegioUp = (data1 & 0x20);
beat->arpegioDown = (data1 & 0x40);
beat->enters = ((beaming - (beaming % 8)) / 8) + 1;
beat->times = (beaming % 8) + 1;
beat->isRest = (data1 & 0x04);
beat->palmMute = data2 & 0x20;
beat->accent = data2 & 0x04;
beat->staccato = data2 & 0x02;
for (int i = int(sec.beats.size()); i < staff + 1; ++i) {
sec.beats.push_back({});
}
if (add) {
sec.beats[staff].push_back(std::shared_ptr<ptBeat>(beat));
}
//sec.getPosition(position).addComponent(beat);
}
std::vector<int> PowerTab::getStaffMap(ptSection& sec)
{
std::vector<int> result;
std::vector<int> slash;
if (!staffInc && curTrack->guitar_ins.size()) {
auto first = curTrack->guitar_ins.front();
while (first.section == sec.number) {
if (first.trackinfo) {
for (unsigned int i = 0; i < curTrack->infos.size(); ++i) {
if ((1 << i) & first.trackinfo) {
result.push_back(i);
}
}
}
if (first.rhytmSlash) {
for (unsigned int i = 0; i < curTrack->infos.size(); ++i) {
if ((i << 1) & first.rhytmSlash) {
slash.push_back(-1 - i);
}
}
}
curTrack->guitar_ins.pop_front();
if (curTrack->guitar_ins.empty()) break;
first = curTrack->guitar_ins.front();
}
}
if (result.empty() || int(result.size()) < sec.staffs) {
result.clear();
if (int(lastStaffMap.size()) < sec.staffs) {
for (int i = 0; i < sec.staffs; ++i) {
result.push_back(i + staffInc);
}
}
else {
result = lastStaffMap;
}
}
for (auto i : slash) {
result.push_back(i);
}
lastStaffMap = result;
return result;
}
//---------------------------------------------------------
// addPalmMate
//---------------------------------------------------------
void PowerTab::addPalmMute(Chord* chord)
{
int track = chord->track();
while (int(_palmMutes.size()) < track + 1)
_palmMutes.push_back(0);
if (_palmMutes[track]) {
PalmMute* pm = _palmMutes[track];
Chord* lastChord = toChord(pm->endCR());
if (lastChord == chord)
return;
//
// extend the current palm mute or start a new one
//
Fraction tick = chord->segment()->tick();
if (pm->tick2() < tick)
_palmMutes[track] = 0;
else {
pm->setTick2(chord->tick() + chord->actualTicks());
pm->setEndElement(chord);
}
}
if (!_palmMutes[track]) {
PalmMute* pm = new PalmMute(score);
_palmMutes[track] = pm;
Segment* segment = chord->segment();
Fraction tick = segment->tick();
pm->setTick(tick);
pm->setTick2(tick + chord->actualTicks());
pm->setTrack(track);
pm->setTrack2(track);
pm->setStartElement(chord);
pm->setEndElement(chord);
score->addElement(pm);
}
}
void PowerTab::fillMeasure(tBeatList& elist, Measure* measure, int staff, std::vector<Note*>& tiedNotes)
{
Tuplet* tuple = nullptr;
int tupleBeatCounter{ 0 };
Fraction tick = measure->tick();
Fraction endtick = measure->endTick();
Chord* hammer{ nullptr };
while (elist.size() && tick < endtick) {
auto beat = elist.front().get();
auto segment = measure->getSegment(SegmentType::ChordRest, tick);
Fraction l(1, beat->duration);
int dots = beat->dotted ? (beat->doubleDotted ? 2 : 1) : (beat->doubleDotted ? 2 : 0);
switch (dots) {
case 1:
l = l + (l * Fraction(1,2));
break;
case 2:
l = l + (l * Fraction(3,4));
break;
}
TDuration d(l);
d.setDots(dots);
if (beat->tuplet || tupleBeatCounter) {
Fraction nt = (l * Fraction(1,3) * Fraction(2,1));
tick += nt;
}
else {
tick += l;
}
ChordRest* cr;
if (beat->notes.empty()) {
auto rest = new Rest(score);
cr = rest;
rest->setTrack(staff * VOICES);
rest->setTicks(l);
rest->setDurationType(d);
segment->add(rest);
}
else {
Chord* chord = new Chord(score);
cr = chord;
chord->setTrack(staff * VOICES);
chord->setTicks(l);
chord->setDurationType(d);
segment->add(chord);
if (beat->palmMute)
addPalmMute(chord);
if (beat->accent) {
auto accent = new Articulation(score);
accent->setSymId(SymId::articAccentAbove);
chord->add(accent);
}
if (beat->staccato) {
auto st = new Articulation(score);
st->setSymId(SymId::articStaccatoAbove);
chord->add(st);
}
bool has_hammer = false;
for (auto n : beat->notes) {
auto note = new Note(score);
chord->add(note);
if (n.dead) {
note->setHeadGroup(NoteHead::Group::HEAD_CROSS);
note->setGhost(true);
}
if (n.hammer) {
has_hammer = true;
}
if (n.tied && tiedNotes[n.str]) {
Tie* tie = new Tie(score);
tie->setEndNote(note);
tiedNotes[n.str]->add(tie);
}
if (n.bend) {
Bend* bend = new Bend(score);
//TODO-ws bend->setNote(note);
bend->points().append(PitchValue(0, n.bend * 25 - 12));
bend->points().append(PitchValue(50, 0));
note->add(bend);
}
if (false && n.slide) {
Text* st = new Text(score, Tid::HARMONY_A);
st->setXmlText(QString("SLIDE %1").arg(n.slide));
st->setTrack(staff * VOICES);
chord->notes().front()->add(st);
}
tiedNotes[n.str] = note;
note->setFret(n.value);
note->setString(n.str);
const StringData* sd = score->staff(staff)->part()->instrument()->stringData();
int k = int(curTrack->infos[staff].strings.size()) - n.str - 1;
int pitch = sd->stringList().at(k).pitch + n.value; //getPitch(n.str, n.value, 0);
note->setPitch(pitch);
note->setTpcFromPitch();
}
if (hammer) {
auto cr1 = hammer;
auto cr2 = chord;
hammer = nullptr;
Slur* slur = new Slur(score);
slur->setStartElement(cr1);
slur->setEndElement(cr2);
slur->setTick(cr1->tick());
slur->setTick2(tick);
slur->setTrack(staff * VOICES);
slur->setTrack2(staff * VOICES);
score->addElement(slur);
Text* st = new Text(score, Tid::HARMONY_A);
st->setXmlText("H");
st->setTrack(staff * VOICES);
cr1->notes().front()->add(st);
}
if (has_hammer) {
hammer = chord;
}
}
if (tupleBeatCounter) {
tupleBeatCounter--;
cr->setTuplet(tuple);
tuple->add(cr);
}
if (beat->tuplet && !tuple) {
tuple = new Tuplet(score);
tuple->setParent(measure);
tuple->setTrack(cr->track());
tuple->setBaseLen(l);
tuple->setRatio(Fraction(3, 2));
tuple->setTicks(l * tuple->ratio().denominator());
cr->setTuplet(tuple);
tuple->add(cr);
tupleBeatCounter = 2;
}
elist.pop_front();
}
if (tick == measure->tick()) {
auto rest = new Rest(score);
rest->setTrack(staff * VOICES);
auto ts = measure->timesig();
rest->setTicks(ts);
rest->setDurationType(TDuration(ts));
measure->getSegment(SegmentType::ChordRest, tick)->add(rest);
}
}
void PowerTab::addToScore(ptSection& sec)
{
cur_section = &sec;
Fraction tick = score->lastMeasure() ? score->lastMeasure()->endTick() : Fraction(0,1);
Fraction lastTS(-1, -1);
bool firstMeasure = true;
if (score->lastMeasure()) {
lastTS = score->lastMeasure()->timesig();
firstMeasure = false;
}
if (firstMeasure) {
//int lastStaff = sec.staffMap.back() + 1;
for (int i = 0; i < staves; ++i) {
Part* part = new Part(score);
Staff* s = new Staff(score);
s->setPart(part);
part->insertStaff(s, -1);
auto info = &curTrack->infos[i];
std::string ss = info->name;
part->setPartName(QString::fromUtf8(ss.data(), int(ss.size())));
part->setPlainLongName(QString::fromUtf8(ss.data(), int(ss.size())));
std::vector<int> reverseStr;
for (auto it = info->strings.rbegin(); it != info->strings.rend(); ++it)
reverseStr.push_back(*it);
StringData stringData(32, int(info->strings.size()), reverseStr.data());
part->instrument()->setStringData(stringData);
part->setMidiProgram(info->instrument);
score->staves().push_back(s);
score->appendPart(part);
}
}
auto bar1 = sec.bars.front();
while (bar1->denominator == 0) {
if (sec.bars.size() == 1)
break;
sec.bars.pop_front();
bar1 = sec.bars.front();
}
if (bar1->denominator == 0) {
bar1->denominator = 4;
bar1->numerator = 4;
}
auto measure = createMeasure(bar1.get(), tick);
if (repeatCount) {
measure->setRepeatEnd(true);
measure->setRepeatCount(repeatCount);
}
repeatCount = bar1->repeatClose;
if (bar1->repeatStart) {
measure->setRepeatStart(true);
}
if (sec.bars.size() > 1) {
sec.bars.pop_front();
}
if (sec.tempo) {
TempoText* tt = new TempoText(score);
tt->setTempo(double(sec.tempo) / 60.0f);
tt->setXmlText(QString("<sym>metNoteQuarterUp</sym> = %1").arg(sec.tempo));
tt->setTrack(0);
Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
segment->add(tt);
score->setTempo(measure->tick(), tt->tempo());
}
if (!sec.partName.empty() && lastPart != sec.partMarker) {
lastPart = sec.partMarker;
RehearsalMark* t = new RehearsalMark(score);
t->setFrameType(FrameType::SQUARE);
t->setPlainText(QString(sec.partMarker));
t->setTrack(0);
auto seg = measure->getSegment(SegmentType::ChordRest, measure->tick());
seg->add(t);
t = new RehearsalMark(score);
t->setFrameType(FrameType::NO_FRAME);
t->setPlainText(QString::fromUtf8(sec.partName.data(), int(sec.partName.size())));
t->setOffset(QPointF(10.0, 0.0));
t->setTrack(0);
seg->add(t);
}
if (firstMeasure) {
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
int keysig = staffIdx >= staffInc ? 0 : 1; // Can be parsed int beat section
KeySig* t = new KeySig(score);
t->setKey(Key(keysig));
t->setTrack(staffIdx * VOICES);
Segment* s = measure->getSegment(SegmentType::KeySig, tick);
s->add(t);
ClefType clefId = staffIdx >= staffInc ? ClefType::F8_VB : ClefType::G15_MB;
auto clef = new Clef(score);
clef->setTrack(staffIdx * VOICES);
clef->setClefType(clefId);
s = measure->getSegment(SegmentType::HeaderClef, Fraction(0,1));
s->add(clef);
}
}
std::vector<std::vector<Note*>> tiedNotes(staves);
for (auto& nvec : tiedNotes) {
nvec.resize(10);
memset(nvec.data(), 0, sizeof(Note*) * 10);
}
//std::vector<tBeatList>
while (true) {
bool empty = true;
while (int(sec.beats.size()) < staves) {
sec.beats.push_back({});
}
for (unsigned int i = 0; i < sec.beats.size(); ++i) {
fillMeasure(sec.beats[i], measure, i, tiedNotes[i]);
if (sec.beats[i].size() && i < unsigned(staffInc))
empty = false;
}
if (lastTS != measure->timesig()) {
lastTS = measure->timesig();
for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
Staff* staff = score->staff(staffIdx);
auto staffType = staff->staffType(Fraction(0,1));
if (staffType->genTimesig()) {
auto t = new TimeSig(score);
t->setTrack(staffIdx * VOICES);
t->setSig(lastTS);
Segment* s = measure->getSegment(SegmentType::TimeSig, measure->tick());
s->add(t);
}
}
}
if (empty) {
break;
}
auto bar = sec.bars.front();
while (bar->denominator == 0) {
if (sec.bars.size() == 1)
break;
sec.bars.pop_front();
bar = sec.bars.front();
}
if (bar->denominator == 0) {
bar->denominator = measure->timesig().denominator();
bar->numerator = measure->timesig().numerator();
}
measure = createMeasure(bar.get(), measure->endTick());
if (repeatCount) {
measure->setRepeatEnd(true);
measure->setRepeatCount(repeatCount);
}
repeatCount = bar->repeatClose;
if (bar->repeatStart) {
measure->setRepeatStart(true);
}
if (sec.bars.size() > 2) {
sec.bars.pop_front();
}
}
if (sec.bars.size()) {
auto bar = sec.bars.back();
if (bar->repeatStart) {
measure->setRepeatStart(true);
}
if (bar->repeatClose) {
measure->setRepeatEnd(true);
measure->setRepeatCount(bar->repeatClose);
}
sec.bars.clear();
}
}
void PowerTab::ptSection::copyTracks(ptTrack* track)
{
//if not found GuitarIn in section or all tracks are readed -> return
if (staffs == int(staffMap.size())) {
return;
}
auto signature = chordTextMap.begin();
for (unsigned index = 0; index < staffMap.size(); ++index) {
auto staff = (staffMap[index] + 1) * -1;
if (staff < 0) {
continue;
}
for (auto rt : rhytm) {
auto newSig = chordTextMap.find(rt.position);
if (newSig != chordTextMap.end()) {
signature = newSig;
}
ptBeat* beat = new ptBeat(staff, 0);
beat->position = rt.position;
beat->duration = rt.duration;
beat->dotted = rt.dotted;
beat->doubleDotted = rt.doubleDotted;
beat->isRest = rt.is_rest;
beat->tuplet = rt.triplet;
if (!rt.is_rest) {
auto diagram = track->diagramMap.find({ {signature->second.key, signature->second.formula, signature->second.formula_mod} });
for (unsigned int string = 0; string < diagram->second.frets.size(); ++string) {
int fret = diagram->second.frets[string];
if (fret >= 0xFE) {
continue;
}
ptNote note;
note.value = fret;
note.str = string;
if (fret == 0xFE) {
note.dead = true;
note.value = 0;
}
beat->notes.emplace_back(note);
}
}
while (int(beats.size()) <= staff) {
beats.push_back({});
}
beats[staff].push_back(shared_ptr<ptBeat>(beat));
}
}
}
void PowerTab::readSection(ptSection& sec)
{
//rect:
readInt(); // left
readInt(); // top
readInt(); // right
readInt(); // bottom
auto lastBarData = readUChar();
skip(4); //spacing from staff
readBarLine(sec);
int itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readDirection(sec);
if (i < itemCount - 1) {
readShort();
}
}
//ChordText section
itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readChordText(sec);
if (i < itemCount - 1) {
readShort();
}
}
//RhytmSlash
itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readRhytmSlash(sec);
if (i < itemCount - 1)
readShort();
}
// Staff
sec.staffs = readHeaderItems();
sec.staffMap = getStaffMap(sec);
for (int i = 0; i < sec.staffs; ++i) {
int staff = sec.staffMap[i];
readStaff(staff, sec);
if (i < sec.staffs - 1) {
readShort();
}
}
sec.copyTracks(curTrack);
// MusicBar section
itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readBarLine(sec);
if (i < itemCount - 1) {
readShort();
}
}
auto bar = new ptBar();
bar->repeatClose = (lastBarData >> 5 == 4) ? lastBarData - 128 : 0;
sec.bars.push_back(shared_ptr<ptBar>(bar));
//sec.getPosition(sec.getNextPositionNumber()).addComponent(bar);
}
void PowerTab::readDirection(ptSection& sec)
{
int position = readUChar();
int symbolCount = readUChar();
for (int i = 0; i < symbolCount; ++i) {
unsigned int data = readShort();
sec.getPosition(position).addComponent(new ptDirection((data >> 8), ((data & 0xC0) >> 6), (data & 0x1F)));
}
}
void PowerTab::readDataInstruments(ptTrack& info)
{
curTrack = &info;
//Guitar section
auto itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readTrackInfo(info);
if (i < itemCount - 1) {
readShort();
}
}
// Chord Diagram Section
itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readChord(info);
if (i < itemCount - 1) {
readShort();
}
}
//Floating Text section
itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readFloatingText();
if (i < itemCount - 1) {
readShort();
}
}
// GuitarIn section
itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readGuitarIn(info);
if (i < itemCount - 1) {
readShort();
}
}
// Tempo marker
itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readTempoMarker(info);
if (i < itemCount - 1) {
readShort();
}
}
//Dynamic section
itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readDynamic();
if (i < itemCount - 1) {
readShort();
}
}
//Symbol section
itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readSectionSymbol(info);
if (i < itemCount - 1) {
readShort();
}
}
//Section section
itemCount = readHeaderItems();
for (int i = 0; i < itemCount; ++i) {
readSection(info.getSection(i));
if (i < itemCount - 1) {
readShort();
}
}
}
std::string crTS(int strings, int tuning[])
{
const static char* tune[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
std::vector<int> pitch;
for (int i = 0; i < strings; ++i) {
pitch.push_back(tuning[i]);
}
std::string t;
for (auto i : pitch) {
t += tune[i % 12];
t += " ";
}
return t;
}
Measure* PowerTab::createMeasure(ptBar* bar, const Fraction& tick)
{
auto measure = new Measure(score);
Fraction nts(bar->numerator, bar->denominator);
measure->setTick(tick);
measure->setTimesig(nts);
measure->setTicks(nts);
score->measures()->add(measure);
return measure;
}
PowerTab::ptSection& PowerTab::ptTrack::getSection(int ind)
{
for (int i = (int)sections.size(); i < ind + 1; ++i) {
sections.push_back(ptSection(i));
}
return sections[ind];
}
PowerTab::ptSection::ptSection(int num)
{
number = num;
}
PowerTab::ptPosition& PowerTab::ptSection::getPosition(int pos)
{
unsigned int i = 0;
while ( i < positions.size() ) {
auto& p = positions[i];
if (p.position == pos) {
return p;
}
++i;
}
ptPosition p;
p.position = pos;
positions.emplace_back(p);
return positions.back();
}
int PowerTab::ptSection::getNextPositionNumber()
{
int next = 0;
unsigned int k = 0;
while (k < positions.size()) {
auto p = positions[k];
next = std::max(next, p.position + 1);
++k;
}
return next;
}
void PowerTab::ptPosition::addComponent(ptComponent* c)
{
components.push_back(shared_ptr<ptComponent>(c));
}
//---------------------------------------------------------
// read
//---------------------------------------------------------
Score::FileError PowerTab::read()
{
if (!readVersion())
return Score::FileError::FILE_BAD_FORMAT;
ptSong song;
readSongInfo(song.info);
readDataInstruments(song.track1);
staffInc = int(song.track1.infos.size());
lastStaffMap.clear();
readDataInstruments(song.track1);
staves = int(song.track1.infos.size());
std::vector<tBeatList> parts(staves);
for (int i = staffInc; i < staves; ++i) {
for (auto& sec : song.track1.sections) {
while (int(sec.beats.size()) < staves)
sec.beats.push_back({});
parts[i].insert(parts[i].end(), sec.beats[i].begin(), sec.beats[i].end());
sec.beats[i].clear();
}
}
for (auto& sec : song.track1.sections) {
for (int i = 0; i < staves; ++i) {
if (parts[i].size()) {
sec.beats[i].insert(sec.beats[i].begin(), parts[i].begin(), parts[i].end());
parts[i].clear();
}
}
addToScore(sec);
for (int i = 0; i < staves; ++i)
parts[i] = sec.beats[i];
}
score->style().set(Sid::ArpeggioHiddenInStdIfTab, true);
MeasureBase* m;
if (!score->measures()->first()) {
m = new VBox(score);
m->setTick(Fraction(0,1));
score->addMeasure(m, 0);
}
else {
m = score->measures()->first();
if (!m->isVBox()) {
MeasureBase* mb = new VBox(score);
mb->setTick(Fraction(0,1));
score->addMeasure(mb, m);
m = mb;
}
}
// create title
std::string name = song.info.name;
if (!name.empty()) {
Text* s = new Text(score, Tid::TITLE);
s->setPlainText(QString::fromUtf8(name.data(), int(name.size())));
m->add(s);
}
// static const char* tune[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
int id = 0;
for (Part* part : score->parts()) {
QMultiMap<int, int> tracks;
Score* pscore = new Score(score);
//TODO-ws pscore->tuning.clear();
auto& info = song.track1.infos[id++];
for (auto it = info.strings.rbegin(); it != info.strings.rend(); ++it) {
//TODO-ws pscore->tuning += tune[*it % 12];
// pscore->tuning += " ";
}
//TODO-ws pscore->showLyrics = score->showLyrics;
pscore->style().set(Sid::createMultiMeasureRests, false);
pscore->style().set(Sid::ArpeggioHiddenInStdIfTab, true);
QList<int> stavesMap;
Part* p = new Part(pscore);
p->setInstrument(*part->instrument());
Staff* staff = part->staves()->front();
Staff* s = new Staff(pscore);
s->setPart(p);
const StaffType* st = staff->staffType(Fraction(0,1));
s->setStaffType(Fraction(0,1), *st);
s->linkTo(staff);
p->staves()->append(s);
pscore->staves().append(s);
stavesMap.append(staff->idx());
for (int i = staff->idx() * VOICES, j = 0; i < staff->idx() * VOICES + VOICES; i++, j++)
tracks.insert(i, j);
Excerpt* excerpt = new Excerpt(score);
excerpt->setTracks(tracks);
excerpt->setPartScore(pscore);
//title?
excerpt->setTitle(part->instrument()->longNames()[0].name());
pscore->setExcerpt(excerpt);
excerpt->parts().append(part);
score->excerpts().append(excerpt);
Excerpt::cloneStaves(score, pscore, stavesMap, tracks);
if (staff->part()->instrument()->stringData()->strings() > 0
&& part->staves()->front()->staffType(Fraction(0,1))->group() == StaffGroup::STANDARD) {
p->setStaves(2);
Staff* s1 = p->staff(1);
int lines = staff->part()->instrument()->stringData()->strings();
StaffTypes sts = StaffTypes::TAB_DEFAULT;
if (lines == 4)
sts = StaffTypes::TAB_4COMMON;
StaffType st1 = *StaffType::preset(sts);
s1->setStaffType(Fraction(0,1), st1);
s1->setLines(Fraction(0,1), lines);
Excerpt::cloneStaff(s, s1);
BracketItem* bi = new BracketItem(pscore, BracketType::NORMAL, 2);
p->staves()->front()->addBracket(bi);
}
pscore->appendPart(p);
//
// create excerpt title
//
MeasureBase* measure = pscore->first();
if (!measure || (measure->type() != ElementType::VBOX)) {
MeasureBase* mb = new VBox(pscore);
mb->setTick(Fraction(0,1));
pscore->addMeasure(mb, measure);
measure = mb;
}
Text* txt = new Text(pscore, Tid::INSTRUMENT_EXCERPT);
txt->setPlainText(part->longName());
measure->add(txt);
pscore->setPlaylistDirty();
pscore->setLayoutAll();
pscore->addLayoutFlags(LayoutFlag::FIX_PITCH_VELO);
pscore->doLayout();
}
return Score::FileError::FILE_NO_ERROR;
}
}