Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #include "importptb.h"
23 : #include "assert.h"
24 :
25 : #include <cmath>
26 :
27 : #include "engraving/dom/articulation.h"
28 : #include "engraving/dom/bend.h"
29 : #include "engraving/dom/box.h"
30 : #include "engraving/dom/chord.h"
31 : #include "engraving/dom/clef.h"
32 : #include "engraving/dom/factory.h"
33 : #include "engraving/dom/instrument.h"
34 : #include "engraving/dom/masterscore.h"
35 : #include "engraving/dom/measure.h"
36 : #include "engraving/dom/note.h"
37 : #include "engraving/dom/palmmute.h"
38 : #include "engraving/dom/part.h"
39 : #include "engraving/dom/rehearsalmark.h"
40 : #include "engraving/dom/rest.h"
41 : #include "engraving/dom/staff.h"
42 : #include "engraving/dom/tempotext.h"
43 : #include "engraving/dom/text.h"
44 : #include "engraving/dom/tie.h"
45 : #include "engraving/dom/timesig.h"
46 : #include "engraving/dom/tuplet.h"
47 :
48 : #include "engraving/types/symid.h"
49 :
50 : #include "log.h"
51 :
52 : using namespace mu::engraving;
53 :
54 : namespace mu::iex::guitarpro {
55 0 : bool PowerTab::readBoolean()
56 : {
57 0 : return readUInt8() != 0;
58 : }
59 :
60 187 : uint8_t PowerTab::readUInt8()
61 : {
62 : uint8_t byte;
63 187 : _file->read((uint8_t*)&byte, 1);
64 187 : return byte;
65 : }
66 :
67 134 : unsigned short PowerTab::readShort()
68 : {
69 : uint16_t val;
70 134 : _file->read((uint8_t*)&val, 2);
71 134 : return val;
72 : }
73 :
74 81 : char PowerTab::readChar()
75 : {
76 : char byte;
77 81 : _file->read((uint8_t*)&byte, 1);
78 81 : return byte;
79 : }
80 :
81 24 : int PowerTab::readInt()
82 : {
83 : int32_t val;
84 24 : _file->read((uint8_t*)&val, 4);
85 24 : return val;
86 : }
87 :
88 19 : std::string PowerTab::readString(int length)
89 : {
90 19 : if (length == 0) {
91 0 : LOGE() << "reading string of length zero";
92 0 : return std::string();
93 : }
94 :
95 19 : if (length == -1) {
96 16 : length = readUInt8();
97 16 : if (length == 0xFF) {
98 0 : length = readShort();
99 : }
100 : }
101 19 : char* p = new char[length];
102 19 : _file->read((uint8_t*)p, length);
103 :
104 19 : std::string s(p, length);
105 19 : delete[] p;
106 19 : return s;
107 19 : }
108 :
109 3 : bool PowerTab::readVersion()
110 : {
111 3 : std::string version = readString(4);
112 9 : version += std::string("-") + std::to_string(readShort());
113 6 : return version == "ptab-4";
114 3 : }
115 :
116 18 : void PowerTab::skip(int len /* = 1 */)
117 : {
118 90 : for (int i = 0; i < len; ++i) {
119 72 : readChar();
120 : }
121 18 : }
122 :
123 3 : void PowerTab::readSongInfo(ptSongInfo& info)
124 : {
125 3 : auto classification = readChar();
126 3 : info.classification = classification;
127 3 : if (classification == 0) {
128 0 : skip(1);
129 0 : info.name = readString();
130 0 : info.interpret = readString();
131 :
132 0 : auto releaseType = readChar();
133 :
134 0 : switch (releaseType) {
135 0 : case 0: {
136 : /*auto albumType =*/
137 0 : readChar();
138 0 : info.album = readString();
139 0 : info.year = readShort();
140 0 : info.liverecording = readChar() != 0;
141 0 : break;
142 : }
143 0 : case 1: {
144 0 : info.album = readString();
145 0 : info.liverecording = readChar() != 0;
146 0 : break;
147 : }
148 0 : case 2: {
149 0 : info.album = readString();
150 0 : info.day = readShort();
151 0 : info.month = readShort();
152 0 : info.year = readShort();
153 0 : break;
154 : }
155 0 : case 3: {
156 0 : break;
157 : }
158 0 : default:
159 0 : assert(0);
160 : }
161 :
162 0 : if (readChar() == 0) {
163 0 : info.author = readString();
164 0 : info.lyricist = readString();
165 : }
166 :
167 0 : info.arranger = readString();
168 0 : info.guitarTranscriber = readString();
169 0 : info.bassTranscriber = readString();
170 0 : info.copyright = readString();
171 :
172 0 : info.lyrics = readString();
173 :
174 0 : info.guitarInstructions = readString();
175 0 : info.bassInstructions = readString();
176 3 : } else if (classification == 1) {
177 0 : info.name = readString();
178 0 : info.album = readString();
179 0 : info.style = readShort();
180 0 : info.level = readUInt8();
181 0 : info.author = readString();
182 0 : info.instructions = readString();
183 0 : info.copyright = readString();
184 : }
185 3 : }
186 :
187 96 : int PowerTab::readHeaderItems()
188 : {
189 96 : int itemCount = readShort();
190 96 : if (itemCount != 0) {
191 29 : int header = readShort();
192 29 : if (header == 0xFFFF) {
193 0 : if (readShort() != 1) {
194 0 : return -1;
195 : }
196 0 : auto str = readString(readShort()); //section title
197 0 : }
198 : }
199 96 : return itemCount;
200 : }
201 :
202 5 : void PowerTab::readTrackInfo(ptTrack& info)
203 : {
204 5 : TrackInfo tr;
205 :
206 5 : tr.number = readUInt8();
207 5 : tr.name = readString();
208 5 : tr.instrument = readUInt8();
209 5 : tr.volume = readUInt8();
210 5 : tr.balance = readUInt8();
211 5 : tr.reverb = readUInt8();
212 5 : tr.chorus = readUInt8();
213 5 : tr.tremolo = readUInt8();
214 5 : tr.phaser = readUInt8();
215 5 : tr.capo = readUInt8();
216 5 : tr.tuningName = readString();
217 5 : tr.offset = readUInt8();
218 :
219 5 : int ln = readUInt8();
220 25 : for (int i = 0; i < ln; ++i) {
221 20 : tr.strings.push_back(readUInt8());
222 : }
223 5 : info.infos.push_back(tr);
224 5 : }
225 :
226 0 : void PowerTab::readChord(ptTrack& info)
227 : {
228 0 : ptChord ch;
229 0 : ch.key = readShort(); //chord key
230 0 : ch.formula = readUInt8();
231 0 : ch.modification = readShort(); //Chord Modification
232 0 : ch.extra = readUInt8();
233 0 : ch.top_fret = readUInt8();
234 0 : auto stringCount = readUInt8();
235 0 : for (int i = 0; i < stringCount; ++i) {
236 0 : ch.frets.push_back(readUInt8()); // fret
237 : }
238 0 : if (info.diagramMap.find({ { ch.key, ch.formula, ch.modification } }) == info.diagramMap.end()) {
239 0 : info.diagramMap[ { { ch.key, ch.formula, ch.modification } }] = ch;
240 : } else {
241 0 : auto a1 = info.diagramMap[ { { ch.key, ch.formula, ch.modification } }];
242 0 : auto a2 = ch;
243 :
244 : //?? int k = 1;
245 0 : }
246 0 : }
247 :
248 0 : void PowerTab::readFontSettings()
249 : {
250 0 : readString(); //font name
251 0 : readInt(); // point size
252 0 : readInt(); // weight
253 0 : readBoolean(); //italic
254 0 : readBoolean(); //underline
255 0 : readBoolean(); //strikeout
256 0 : readInt(); //color
257 0 : }
258 :
259 0 : void PowerTab::readFloatingText()
260 : {
261 0 : readString(); //text
262 : //rect :
263 0 : readInt(); // left
264 0 : readInt(); // top
265 0 : readInt(); // right
266 0 : readInt(); // bottom
267 :
268 0 : readUInt8();
269 0 : readFontSettings();
270 0 : }
271 :
272 0 : void PowerTab::readDynamic()
273 : {
274 0 : readShort();
275 0 : readUInt8();
276 0 : readUInt8();
277 0 : readShort();
278 0 : }
279 :
280 6 : void PowerTab::readKeySignature()
281 : {
282 6 : readUInt8();
283 6 : }
284 :
285 6 : void PowerTab::readRehearsalSign(ptSection& sec)
286 : {
287 6 : auto c = readChar();
288 6 : auto str = readString();
289 6 : if (str.size()) {
290 0 : sec.partName = str;
291 0 : sec.partMarker = c;
292 : }
293 6 : }
294 :
295 0 : void PowerTab::readChordText(ptSection& sec)
296 : {
297 0 : ptChordText cht;
298 0 : cht.position = readUInt8();
299 0 : cht.key = readShort();
300 0 : cht.formula = readUInt8();
301 0 : cht.formula_mod = readShort();
302 0 : cht.extra = readUInt8();
303 : //sec.chordTextMap.push_back(cht);
304 0 : sec.chordTextMap.insert({ cht.position, cht });
305 0 : }
306 :
307 0 : void PowerTab::readRhytmSlash(ptSection& sec)
308 : {
309 0 : stRhytmSlash rs;
310 0 : rs.position = readUInt8();
311 0 : auto beaming = readUInt8();
312 0 : auto data = readInt();
313 0 : auto duration = (data & 0xE00000) >> 21;
314 0 : switch (duration) {
315 0 : case 0:
316 0 : rs.duration = 1;
317 0 : break;
318 0 : case 1:
319 0 : rs.duration = 2;
320 0 : break;
321 0 : case 2:
322 0 : rs.duration = 4;
323 0 : break;
324 0 : case 3:
325 0 : rs.duration = 8;
326 0 : break;
327 0 : case 4:
328 0 : rs.duration = 16;
329 : }
330 :
331 0 : rs.triplet = beaming & (0x20 | 0x40);
332 0 : rs.tripletend = beaming & 0x80;
333 :
334 0 : rs.dotted = data & 0x01;
335 0 : rs.doubleDotted = data & 0x02;
336 :
337 0 : rs.is_rest = data & 0x04;
338 :
339 0 : sec.rhythm.emplace_back(rs);
340 0 : }
341 :
342 0 : void PowerTab::readGuitarIn(ptTrack& info)
343 : {
344 0 : ptGuitarIn gin;
345 0 : gin.section = readShort();
346 0 : gin.staff = readUInt8() + staffInc;
347 0 : gin.position = readUInt8();
348 0 : gin.rhythmSlash = readUInt8();
349 0 : gin.trackinfo = readUInt8();
350 0 : info.guitar_ins.push_back(gin);
351 0 : }
352 :
353 0 : void PowerTab::readTempoMarker(ptTrack& info)
354 : {
355 0 : auto section = readShort();
356 0 : /*auto position =*/ readUInt8();
357 0 : auto tempo = readShort();
358 0 : /*auto data =*/ readShort();
359 0 : readString(); //description
360 :
361 0 : if (tempo > 0) {
362 0 : info.getSection(section).tempo = tempo;
363 : }
364 0 : }
365 :
366 0 : void PowerTab::readSectionSymbol(ptTrack& info)
367 : {
368 0 : int section = readShort();
369 0 : int position = readUInt8();
370 0 : int data = readInt();
371 :
372 0 : int endNumber = data >> 16;
373 0 : info.getSection(section).getPosition(position).addComponent(new ptSymbol(endNumber));
374 0 : }
375 :
376 6 : void PowerTab::readTimeSignature(ptBar* bar)
377 : {
378 6 : skip(3);
379 6 : int data = readUInt8();
380 6 : readUInt8(); // measure pulses
381 :
382 6 : bar->numerator = ((data - (data % 8)) / 8) + 1;
383 6 : bar->denominator = pow(2, data % 8);
384 6 : }
385 :
386 6 : void PowerTab::readBarLine(ptSection& sec)
387 : {
388 6 : auto bar = new ptBar();
389 6 : /*int position =*/ readUInt8();
390 6 : auto b_type = readUInt8();
391 :
392 6 : bar->repeatStart = (b_type >> 5) == 3;
393 6 : bar->repeatClose = (b_type >> 5) == 4 ? b_type - 128 : 0;
394 :
395 6 : bar->measureNo = sec.number;
396 :
397 6 : readKeySignature();
398 6 : readTimeSignature(bar);
399 6 : readRehearsalSign(sec);
400 : //sec.getPosition(position).addComponent(bar);
401 6 : sec.bars.push_back(std::shared_ptr<ptBar>(bar));
402 : /*if (bars.empty() || ( bars.back()->measureNo < bar->measureNo ))
403 : bars.push_back(bar);*/
404 6 : }
405 :
406 6 : void PowerTab::readStaff(int staff, ptSection& sec)
407 : {
408 6 : skip(5);
409 18 : for (int voice = 0; voice < 2; ++voice) {
410 12 : int itemCount = readHeaderItems();
411 18 : for (int i = 0; i < itemCount; ++i) {
412 6 : readPosition(staff, voice, sec);
413 6 : if (i < itemCount - 1) {
414 0 : readShort();
415 : }
416 : }
417 : }
418 6 : }
419 :
420 6 : void PowerTab::readNote(ptBeat* beat)
421 : {
422 6 : ptNote note;
423 6 : auto position = readUInt8();
424 6 : auto simpleData = readShort();
425 6 : auto symbolCount = readUInt8();
426 6 : for (int i = 0; i < symbolCount; ++i) {
427 0 : skip(2);
428 0 : auto data3 = readUInt8();
429 0 : auto data4 = readUInt8();
430 0 : note.bend = data4 == 101 ? data3 / 16 + 1 : 0;
431 0 : note.slide = data4 == 100 ? data3 + 1 : 0;
432 : }
433 6 : note.value = position & 0x1F;
434 6 : note.str = ((position & 0xE0) >> 5);
435 6 : note.tied = simpleData & 0x01;
436 6 : note.dead = simpleData & 0x02;
437 6 : note.hammer = simpleData & 0x08;
438 6 : beat->notes.emplace_back(note);
439 6 : }
440 :
441 6 : void PowerTab::readPosition(int staff, int voice, ptSection& sec)
442 : {
443 6 : auto position = readUInt8();
444 :
445 6 : ptBeat beat = ptBeat();
446 6 : beat.position = position;
447 6 : beat.voice = voice;
448 6 : bool add = false;
449 6 : if (voice == 0 || static_cast<size_t>(staff) >= sec.beats.size() || sec.beats[staff].empty()) {
450 6 : beat = ptBeat(staff, voice);
451 6 : beat.position = position;
452 6 : add = true;
453 : }
454 6 : auto beaming = readUInt8();
455 6 : beaming = (((int)beaming - 128 < 0) ? beaming : beaming - 128);
456 :
457 6 : readUInt8();
458 :
459 6 : auto data1 = readUInt8();
460 6 : auto data2 = readUInt8(); //32 - palm mute, 4 - accent, 2 - staccato
461 6 : auto data3 = readUInt8();
462 6 : auto durationValue = readUInt8();
463 :
464 6 : int multiBarRest = 1;
465 6 : auto complexCount = readUInt8();
466 6 : for (int i = 0; i < complexCount; ++i) {
467 0 : auto count = readShort();
468 0 : readUInt8();
469 0 : auto type = readUInt8();
470 0 : if (type & 0x08) {
471 0 : multiBarRest = count;
472 : }
473 : }
474 :
475 6 : auto itemCount = readHeaderItems();
476 12 : for (int i = 0; i < itemCount; ++i) {
477 6 : readNote(&beat);
478 6 : if (i < itemCount - 1) {
479 0 : readShort();
480 : }
481 : }
482 :
483 6 : if (staff < 0 || staff >= static_cast<int>(curTrack->infos.size())) {
484 1 : LOGE() << "Invalid staff index";
485 1 : return;
486 : }
487 5 : curTrack->infos[staff].notes_count += itemCount;
488 :
489 5 : beat.mmrest = (itemCount == 0) ? multiBarRest : 1;
490 5 : beat.vibrato = (((data1 & 0x08) != 0) || ((data1 & 0x10) != 0));
491 5 : beat.grace = (data3 & 0x01) != 0;
492 5 : beat.tuplet = (data3 & 0x20) != 0;
493 :
494 5 : if (beat.duration != 0) {
495 0 : durationValue = std::max((int)durationValue, beat.duration);
496 : }
497 :
498 5 : beat.duration = durationValue;
499 5 : beat.dotted = (data1 & 0x01);
500 5 : beat.doubleDotted = (data1 & 0x02);
501 5 : beat.arpeggioUp = (data1 & 0x20);
502 5 : beat.arpeggioDown = (data1 & 0x40);
503 5 : beat.enters = ((beaming - (beaming % 8)) / 8) + 1;
504 5 : beat.times = (beaming % 8) + 1;
505 5 : beat.isRest = (data1 & 0x04);
506 5 : beat.palmMute = data2 & 0x20;
507 5 : beat.accent = data2 & 0x04;
508 5 : beat.staccato = data2 & 0x02;
509 :
510 10 : for (int i = int(sec.beats.size()); i < staff + 1; ++i) {
511 5 : sec.beats.push_back({});
512 : }
513 5 : if (add) {
514 5 : sec.beats[staff].push_back(beat);
515 : }
516 : //sec.getPosition(position).addComponent(beat);
517 6 : }
518 :
519 6 : std::vector<int> PowerTab::getStaffMap(ptSection& sec)
520 : {
521 6 : std::vector<int> result;
522 6 : std::vector<int> slash;
523 6 : if (!staffInc && curTrack->guitar_ins.size()) {
524 0 : auto first = curTrack->guitar_ins.front();
525 0 : while (first.section == sec.number) {
526 0 : if (first.trackinfo) {
527 0 : for (unsigned int i = 0; i < curTrack->infos.size(); ++i) {
528 0 : if ((1 << i) & first.trackinfo) {
529 0 : result.push_back(i);
530 : }
531 : }
532 : }
533 :
534 0 : if (first.rhythmSlash) {
535 0 : for (unsigned int i = 0; i < curTrack->infos.size(); ++i) {
536 0 : if ((i << 1) & first.rhythmSlash) {
537 0 : slash.push_back(-1 - i);
538 : }
539 : }
540 : }
541 :
542 0 : curTrack->guitar_ins.pop_front();
543 0 : if (curTrack->guitar_ins.empty()) {
544 0 : break;
545 : }
546 0 : first = curTrack->guitar_ins.front();
547 : }
548 0 : }
549 :
550 6 : if (result.empty() || int(result.size()) < sec.staves) {
551 6 : result.clear();
552 6 : if (int(lastStaffMap.size()) < sec.staves) {
553 12 : for (int i = 0; i < sec.staves; ++i) {
554 6 : result.push_back(i + staffInc);
555 : }
556 : } else {
557 0 : result = lastStaffMap;
558 : }
559 : }
560 :
561 : // negative numbers
562 : // for (auto i : slash) {
563 : // result.push_back(i);
564 : // }
565 :
566 6 : lastStaffMap = result;
567 6 : return result;
568 6 : }
569 :
570 : //---------------------------------------------------------
571 : // addPalmMate
572 : //---------------------------------------------------------
573 :
574 0 : void PowerTab::addPalmMute(Chord* chord)
575 : {
576 0 : track_idx_t track = chord->track();
577 0 : while (_palmMutes.size() < track + 1) {
578 0 : _palmMutes.push_back(0);
579 : }
580 :
581 0 : if (_palmMutes[track]) {
582 0 : PalmMute* pm = _palmMutes[track];
583 0 : Chord* lastChord = toChord(pm->endCR());
584 0 : if (lastChord == chord) {
585 0 : return;
586 : }
587 : //
588 : // extend the current palm mute or start a new one
589 : //
590 0 : Fraction tick = chord->segment()->tick();
591 0 : if (pm->tick2() < tick) {
592 0 : _palmMutes[track] = 0;
593 : } else {
594 0 : pm->setTick2(chord->endTick());
595 0 : pm->setEndElement(chord);
596 : }
597 : }
598 0 : if (!_palmMutes[track]) {
599 0 : PalmMute* pm = new PalmMute(score->dummy());
600 0 : _palmMutes[track] = pm;
601 0 : Segment* segment = chord->segment();
602 0 : Fraction tick = segment->tick();
603 :
604 0 : pm->setTick(tick);
605 0 : pm->setTick2(tick + chord->actualTicks());
606 0 : pm->setTrack(track);
607 0 : pm->setTrack2(track);
608 0 : pm->setStartElement(chord);
609 0 : pm->setEndElement(chord);
610 0 : score->addElement(pm);
611 : }
612 : }
613 :
614 5 : void PowerTab::fillMeasure(tBeatList& elist, Measure* measure, int staff, std::vector<Note*>& tiedNotes)
615 : {
616 5 : Tuplet* tuple = nullptr;
617 5 : int tupleBeatCounter{ 0 };
618 5 : Fraction tick = measure->tick();
619 5 : Fraction endtick = measure->endTick();
620 5 : Chord* hammer{ nullptr };
621 :
622 10 : while (elist.size() && tick < endtick) {
623 5 : auto& beat = elist.front();
624 5 : auto segment = measure->getSegment(SegmentType::ChordRest, tick);
625 5 : Fraction l(1, beat.duration);
626 5 : int dots = beat.dotted ? (beat.doubleDotted ? 2 : 1) : (beat.doubleDotted ? 2 : 0);
627 5 : switch (dots) {
628 0 : case 1:
629 0 : l = l + (l * Fraction(1, 2));
630 0 : break;
631 0 : case 2:
632 0 : l = l + (l * Fraction(3, 4));
633 0 : break;
634 : }
635 :
636 5 : TDuration d(l);
637 5 : d.setDots(dots);
638 :
639 5 : if (beat.tuplet || tupleBeatCounter) {
640 0 : Fraction nt = (l * Fraction(1, 3) * Fraction(2, 1));
641 0 : tick += nt;
642 0 : } else {
643 5 : tick += l;
644 : }
645 : ChordRest* cr;
646 5 : if (beat.notes.empty()) {
647 0 : auto rest = Factory::createRest(segment);
648 0 : cr = rest;
649 0 : rest->setTrack(staff * VOICES);
650 0 : rest->setTicks(l);
651 0 : rest->setDurationType(d);
652 0 : segment->add(rest);
653 : } else {
654 5 : Chord* chord = Factory::createChord(segment);
655 5 : cr = chord;
656 5 : chord->setTrack(staff * VOICES);
657 5 : chord->setTicks(l);
658 5 : chord->setDurationType(d);
659 5 : segment->add(chord);
660 :
661 5 : if (beat.palmMute) {
662 0 : addPalmMute(chord);
663 : }
664 5 : if (beat.accent) {
665 0 : auto accent = Factory::createArticulation(chord);
666 0 : accent->setSymId(SymId::articAccentAbove);
667 0 : chord->add(accent);
668 : }
669 5 : if (beat.staccato) {
670 0 : auto st = Factory::createArticulation(chord);
671 0 : st->setSymId(SymId::articStaccatoAbove);
672 0 : chord->add(st);
673 : }
674 5 : bool has_hammer = false;
675 10 : for (const auto& n : beat.notes) {
676 5 : if (n.str < 0 || static_cast<size_t>(n.str) >= tiedNotes.size()) {
677 0 : LOGE() << "string index out of range, skipping note";
678 0 : continue;
679 : }
680 :
681 5 : const std::vector<int>& trackStrings = curTrack->infos[staff].strings;
682 5 : if (trackStrings.empty()) {
683 1 : LOGE() << "track has no strings, skipping note";
684 1 : continue;
685 : }
686 :
687 4 : const StringData* sd = score->staff(staff)->part()->instrument()->stringData();
688 4 : const int k = std::max(int(trackStrings.size()) - n.str - 1, 0);
689 4 : if (!sd || static_cast<size_t>(k) >= sd->stringList().size()) {
690 0 : LOGE() << "string data missing for note pitch";
691 0 : continue;
692 : }
693 :
694 4 : auto note = Factory::createNote(chord);
695 4 : chord->add(note);
696 4 : if (n.dead) {
697 0 : note->setHeadGroup(NoteHeadGroup::HEAD_CROSS);
698 0 : note->setGhost(true);
699 : }
700 :
701 4 : if (n.hammer) {
702 0 : has_hammer = true;
703 : }
704 :
705 4 : if (n.tied && tiedNotes[n.str]) {
706 0 : Tie* tie = Factory::createTie(tiedNotes[n.str]);
707 0 : tie->setEndNote(note);
708 0 : tiedNotes[n.str]->add(tie);
709 : }
710 :
711 4 : if (n.bend) {
712 0 : Bend* bend = Factory::createBend(note);
713 : //TODO-ws bend->setNote(note);
714 0 : bend->points().push_back(PitchValue(0, n.bend * 25 - 12));
715 0 : bend->points().push_back(PitchValue(50, 0));
716 0 : note->add(bend);
717 : }
718 :
719 : if (false && n.slide) {
720 : Text* st = Factory::createText(chord->notes().front(), TextStyleType::HARMONY_A);
721 : st->setXmlText(String(u"SLIDE %1").arg(n.slide));
722 : st->setTrack(staff * VOICES);
723 : chord->notes().front()->add(st);
724 : }
725 :
726 4 : tiedNotes[n.str] = note;
727 4 : note->setFret(n.value);
728 4 : note->setString(n.str);
729 4 : int pitch = sd->stringList().at(k).pitch + n.value; //getPitch(n.str, n.value, 0);
730 4 : note->setPitch(pitch);
731 4 : note->setTpcFromPitch();
732 : }
733 :
734 5 : if (hammer) {
735 0 : auto cr1 = hammer;
736 0 : auto cr2 = chord;
737 0 : hammer = nullptr;
738 :
739 0 : Slur* slur = Factory::createSlur(score->dummy());
740 0 : slur->setStartElement(cr1);
741 0 : slur->setEndElement(cr2);
742 0 : slur->setTick(cr1->tick());
743 0 : slur->setTick2(tick);
744 0 : slur->setTrack(staff * VOICES);
745 0 : slur->setTrack2(staff * VOICES);
746 0 : score->addElement(slur);
747 :
748 0 : Text* st = Factory::createText(chord->notes().front(), TextStyleType::HARMONY_A);
749 0 : st->setXmlText(u"H");
750 0 : st->setTrack(staff * VOICES);
751 0 : cr1->notes().front()->add(st);
752 : }
753 5 : if (has_hammer) {
754 0 : hammer = chord;
755 : }
756 : }
757 :
758 5 : if (tupleBeatCounter && tuple) {
759 0 : tupleBeatCounter--;
760 0 : cr->setTuplet(tuple);
761 0 : tuple->add(cr);
762 : }
763 :
764 5 : if (beat.tuplet && !tuple) {
765 0 : tuple = Factory::createTuplet(measure);
766 0 : tuple->setTrack(cr->track());
767 0 : tuple->setTick(cr->tick());
768 0 : tuple->setBaseLen(l);
769 0 : tuple->setRatio(Fraction(3, 2));
770 0 : tuple->setTicks(l * tuple->ratio().denominator());
771 0 : cr->setTuplet(tuple);
772 0 : tuple->add(cr);
773 0 : tupleBeatCounter = 2;
774 : }
775 5 : elist.pop_front();
776 : }
777 :
778 5 : if (tick == measure->tick()) {
779 0 : Segment* seg = measure->getSegment(SegmentType::ChordRest, tick);
780 0 : auto rest = Factory::createRest(seg);
781 0 : rest->setTrack(staff * VOICES);
782 0 : auto ts = measure->timesig();
783 0 : rest->setTicks(ts);
784 0 : rest->setDurationType(TDuration(ts));
785 0 : seg->add(rest);
786 : }
787 5 : }
788 :
789 3 : void PowerTab::addToScore(ptSection& sec)
790 : {
791 3 : cur_section = &sec;
792 3 : Fraction tick = score->lastMeasure() ? score->lastMeasure()->endTick() : Fraction(0, 1);
793 :
794 3 : Fraction lastTS(-1, -1);
795 3 : bool firstMeasure = true;
796 3 : if (score->lastMeasure()) {
797 0 : lastTS = score->lastMeasure()->timesig();
798 0 : firstMeasure = false;
799 : }
800 3 : if (firstMeasure) {
801 : //int lastStaff = sec.staffMap.back() + 1;
802 8 : for (int i = 0; i < staves; ++i) {
803 5 : Part* part = new Part(score);
804 5 : Staff* s = Factory::createStaff(part);
805 5 : auto info = &curTrack->infos[i];
806 5 : std::string ss = info->name;
807 5 : String staffName;
808 5 : if (muse::UtfCodec::isValidUtf8(ss)) {
809 5 : staffName = muse::String::fromStdString(ss);
810 : } else {
811 : // invalid utf most likely windows-125x used
812 0 : std::string n = "part " + std::to_string(i + 1);
813 0 : staffName = muse::String::fromStdString(n);
814 0 : }
815 5 : part->setPlainLongName(staffName);
816 :
817 5 : std::vector<int> reverseStr;
818 25 : for (auto it = info->strings.rbegin(); it != info->strings.rend(); ++it) {
819 20 : reverseStr.push_back(*it);
820 : }
821 5 : StringData stringData(32, int(info->strings.size()), reverseStr.data());
822 5 : part->instrument()->setStringData(stringData);
823 :
824 5 : part->setMidiProgram(info->instrument);
825 5 : part->setMidiChannel(info->number);
826 :
827 5 : score->appendStaff(s);
828 5 : score->appendPart(part);
829 5 : }
830 : }
831 3 : auto bar1 = sec.bars.front();
832 3 : while (bar1->denominator == 0) {
833 0 : if (sec.bars.size() == 1) {
834 0 : break;
835 : }
836 0 : sec.bars.pop_front();
837 0 : bar1 = sec.bars.front();
838 : }
839 3 : if (bar1->denominator == 0) {
840 0 : bar1->denominator = 4;
841 0 : bar1->numerator = 4;
842 : }
843 3 : auto measure = createMeasure(bar1.get(), tick);
844 3 : if (repeatCount) {
845 0 : measure->setRepeatEnd(true);
846 0 : measure->setRepeatCount(repeatCount);
847 : }
848 3 : repeatCount = bar1->repeatClose;
849 3 : if (bar1->repeatStart) {
850 0 : measure->setRepeatStart(true);
851 : }
852 3 : if (sec.bars.size() > 1) {
853 3 : sec.bars.pop_front();
854 : }
855 3 : if (sec.tempo) {
856 0 : Segment* segment = measure->getSegment(SegmentType::ChordRest, measure->tick());
857 0 : TempoText* tt = new TempoText(segment);
858 0 : tt->setTempo(double(sec.tempo) / 60.0f);
859 0 : tt->setXmlText(String(u"<sym>metNoteQuarterUp</sym> = %1").arg(sec.tempo));
860 0 : tt->setTrack(0);
861 0 : segment->add(tt);
862 : }
863 3 : if (!sec.partName.empty() && lastPart != sec.partMarker) {
864 0 : lastPart = sec.partMarker;
865 0 : auto seg = measure->getSegment(SegmentType::ChordRest, measure->tick());
866 0 : RehearsalMark* t = new RehearsalMark(seg);
867 0 : t->setFrameType(FrameType::RECTANGLE);
868 0 : t->setPlainText(String(Char::fromAscii(sec.partMarker)));
869 0 : t->setTrack(0);
870 0 : seg->add(t);
871 :
872 0 : t = new RehearsalMark(seg);
873 0 : t->setFrameType(FrameType::NO_FRAME);
874 0 : std::string valid;
875 0 : muse::UtfCodec::replaceInvalid(sec.partName, valid);
876 0 : t->setPlainText(String::fromStdString(valid));
877 0 : t->setOffset(PointF(10.0, 0.0));
878 0 : t->setTrack(0);
879 0 : seg->add(t);
880 0 : }
881 3 : if (firstMeasure) {
882 8 : for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
883 5 : int keysig = staffIdx >= staffInc ? 0 : 1; // Can be parsed int beat section
884 5 : Segment* s = measure->getSegment(SegmentType::KeySig, tick);
885 5 : KeySig* t = Factory::createKeySig(s);
886 5 : t->setKey(Key(keysig));
887 5 : t->setTrack(staffIdx * VOICES);
888 5 : s->add(t);
889 :
890 5 : ClefType clefId = staffIdx >= staffInc ? ClefType::F8_VB : ClefType::G15_MB;
891 5 : s = measure->getSegment(SegmentType::HeaderClef, Fraction(0, 1));
892 5 : auto clef = Factory::createClef(s);
893 5 : clef->setTrack(staffIdx * VOICES);
894 5 : clef->setClefType(clefId);
895 5 : s->add(clef);
896 : }
897 : }
898 :
899 3 : std::vector<std::vector<Note*> > tiedNotes(staves);
900 8 : for (auto& nvec : tiedNotes) {
901 5 : nvec.resize(10);
902 5 : memset(nvec.data(), 0, sizeof(Note*) * 10);
903 : }
904 :
905 3 : if (sec.beats.size() > static_cast<size_t>(staves)) {
906 0 : LOGE() << "Found more beat lists than staves, some beat lists will be skipped";
907 : }
908 :
909 : //std::vector<tBeatList>
910 : while (true) {
911 3 : bool empty = true;
912 3 : while (int(sec.beats.size()) < staves) {
913 0 : sec.beats.push_back({});
914 : }
915 8 : for (unsigned int i = 0; i < sec.beats.size() && i < tiedNotes.size(); ++i) {
916 5 : fillMeasure(sec.beats[i], measure, i, tiedNotes[i]);
917 5 : if (sec.beats[i].size() && i < unsigned(staffInc)) {
918 0 : empty = false;
919 : }
920 : }
921 3 : if (lastTS != measure->timesig()) {
922 0 : lastTS = measure->timesig();
923 0 : for (int staffIdx = 0; staffIdx < staves; ++staffIdx) {
924 0 : Staff* staff = score->staff(staffIdx);
925 0 : auto staffType = staff->staffType(Fraction(0, 1));
926 0 : if (staffType->genTimesig()) {
927 0 : Segment* s = measure->getSegment(SegmentType::TimeSig, measure->tick());
928 0 : auto t = Factory::createTimeSig(s);
929 0 : t->setTrack(staffIdx * VOICES);
930 0 : t->setSig(lastTS);
931 0 : s->add(t);
932 : }
933 : }
934 : }
935 3 : if (empty) {
936 3 : break;
937 : }
938 0 : auto bar = sec.bars.front();
939 0 : while (bar->denominator == 0) {
940 0 : if (sec.bars.size() == 1) {
941 0 : break;
942 : }
943 0 : sec.bars.pop_front();
944 0 : bar = sec.bars.front();
945 : }
946 0 : if (bar->denominator == 0) {
947 0 : bar->denominator = measure->timesig().denominator();
948 0 : bar->numerator = measure->timesig().numerator();
949 : }
950 0 : measure = createMeasure(bar.get(), measure->endTick());
951 0 : if (repeatCount) {
952 0 : measure->setRepeatEnd(true);
953 0 : measure->setRepeatCount(repeatCount);
954 : }
955 0 : repeatCount = bar->repeatClose;
956 0 : if (bar->repeatStart) {
957 0 : measure->setRepeatStart(true);
958 : }
959 0 : if (sec.bars.size() > 2) {
960 0 : sec.bars.pop_front();
961 : }
962 0 : }
963 3 : if (sec.bars.size()) {
964 3 : auto bar = sec.bars.back();
965 3 : if (bar->repeatStart) {
966 0 : measure->setRepeatStart(true);
967 : }
968 3 : if (bar->repeatClose) {
969 0 : measure->setRepeatEnd(true);
970 0 : measure->setRepeatCount(bar->repeatClose);
971 : }
972 3 : sec.bars.clear();
973 3 : }
974 3 : }
975 :
976 6 : void PowerTab::ptSection::copyTracks(ptTrack* track)
977 : {
978 : //if not found GuitarIn in section or all tracks are read -> return
979 6 : if (staves == int(staffMap.size())) {
980 6 : return;
981 : }
982 :
983 0 : auto signature = chordTextMap.begin();
984 0 : for (unsigned index = 0; index < staffMap.size(); ++index) {
985 0 : auto staff = (staffMap[index] + 1) * -1;
986 0 : if (staff < 0) {
987 0 : continue;
988 : }
989 :
990 0 : for (const auto& rt : rhythm) {
991 0 : auto newSig = chordTextMap.find(rt.position);
992 0 : if (newSig != chordTextMap.end()) {
993 0 : signature = newSig;
994 : }
995 :
996 0 : ptBeat beat = ptBeat(staff, 0);
997 0 : beat.position = rt.position;
998 0 : beat.duration = rt.duration;
999 0 : beat.dotted = rt.dotted;
1000 0 : beat.doubleDotted = rt.doubleDotted;
1001 0 : beat.isRest = rt.is_rest;
1002 0 : beat.tuplet = rt.triplet;
1003 0 : if (!rt.is_rest) {
1004 0 : auto diagram = track->diagramMap.find({ { signature->second.key, signature->second.formula,
1005 0 : signature->second.formula_mod } });
1006 :
1007 0 : if (diagram != track->diagramMap.end()) {
1008 0 : for (unsigned int string = 0; string < diagram->second.frets.size(); ++string) {
1009 0 : int fret = diagram->second.frets[string];
1010 0 : if (fret >= 0xFE) {
1011 0 : continue;
1012 : }
1013 0 : ptNote note;
1014 0 : note.value = fret;
1015 0 : note.str = string;
1016 0 : if (fret == 0xFE) {
1017 0 : note.dead = true;
1018 0 : note.value = 0;
1019 : }
1020 0 : beat.notes.emplace_back(note);
1021 0 : }
1022 : } else {
1023 0 : LOGD() << "diagram wasn't found";
1024 : }
1025 : }
1026 0 : while (int(beats.size()) <= staff) {
1027 0 : beats.push_back({});
1028 : }
1029 0 : beats[staff].push_back(beat);
1030 0 : }
1031 : }
1032 : }
1033 :
1034 6 : void PowerTab::readSection(ptSection& sec)
1035 : {
1036 : //rect:
1037 6 : readInt(); // left
1038 6 : readInt(); // top
1039 6 : readInt(); // right
1040 6 : readInt(); // bottom
1041 :
1042 6 : auto lastBarData = readUInt8();
1043 :
1044 6 : skip(4); //spacing from staff
1045 :
1046 6 : readBarLine(sec);
1047 :
1048 6 : int itemCount = readHeaderItems();
1049 6 : for (int i = 0; i < itemCount; ++i) {
1050 0 : readDirection(sec);
1051 0 : if (i < itemCount - 1) {
1052 0 : readShort();
1053 : }
1054 : }
1055 : //ChordText section
1056 6 : itemCount = readHeaderItems();
1057 6 : for (int i = 0; i < itemCount; ++i) {
1058 0 : readChordText(sec);
1059 0 : if (i < itemCount - 1) {
1060 0 : readShort();
1061 : }
1062 : }
1063 : //RhytmSlash
1064 6 : itemCount = readHeaderItems();
1065 6 : for (int i = 0; i < itemCount; ++i) {
1066 0 : readRhytmSlash(sec);
1067 0 : if (i < itemCount - 1) {
1068 0 : readShort();
1069 : }
1070 : }
1071 : // Staff
1072 6 : sec.staves = readHeaderItems();
1073 6 : sec.staffMap = getStaffMap(sec);
1074 12 : for (int i = 0; i < sec.staves; ++i) {
1075 6 : int staff = sec.staffMap[i];
1076 6 : readStaff(staff, sec);
1077 6 : if (i < sec.staves - 1) {
1078 0 : readShort();
1079 : }
1080 : }
1081 6 : sec.copyTracks(curTrack);
1082 : // MusicBar section
1083 6 : itemCount = readHeaderItems();
1084 6 : for (int i = 0; i < itemCount; ++i) {
1085 0 : readBarLine(sec);
1086 0 : if (i < itemCount - 1) {
1087 0 : readShort();
1088 : }
1089 : }
1090 :
1091 6 : auto bar = new ptBar();
1092 6 : bar->repeatClose = (lastBarData >> 5 == 4) ? lastBarData - 128 : 0;
1093 6 : sec.bars.push_back(std::shared_ptr<ptBar>(bar));
1094 : //sec.getPosition(sec.getNextPositionNumber()).addComponent(bar);
1095 6 : }
1096 :
1097 0 : void PowerTab::readDirection(ptSection& sec)
1098 : {
1099 0 : int position = readUInt8();
1100 0 : int symbolCount = readUInt8();
1101 0 : for (int i = 0; i < symbolCount; ++i) {
1102 0 : unsigned int data = readShort();
1103 0 : sec.getPosition(position).addComponent(new ptDirection((data >> 8), ((data & 0xC0) >> 6), (data & 0x1F)));
1104 : }
1105 0 : }
1106 :
1107 6 : void PowerTab::readDataInstruments(ptTrack& info)
1108 : {
1109 6 : curTrack = &info;
1110 : //Guitar section
1111 6 : auto itemCount = readHeaderItems();
1112 11 : for (int i = 0; i < itemCount; ++i) {
1113 5 : readTrackInfo(info);
1114 5 : if (i < itemCount - 1) {
1115 0 : readShort();
1116 : }
1117 : }
1118 : // Chord Diagram Section
1119 6 : itemCount = readHeaderItems();
1120 6 : for (int i = 0; i < itemCount; ++i) {
1121 0 : readChord(info);
1122 0 : if (i < itemCount - 1) {
1123 0 : readShort();
1124 : }
1125 : }
1126 : //Floating Text section
1127 6 : itemCount = readHeaderItems();
1128 6 : for (int i = 0; i < itemCount; ++i) {
1129 0 : readFloatingText();
1130 0 : if (i < itemCount - 1) {
1131 0 : readShort();
1132 : }
1133 : }
1134 : // GuitarIn section
1135 6 : itemCount = readHeaderItems();
1136 6 : for (int i = 0; i < itemCount; ++i) {
1137 0 : readGuitarIn(info);
1138 0 : if (i < itemCount - 1) {
1139 0 : readShort();
1140 : }
1141 : }
1142 : // Tempo marker
1143 6 : itemCount = readHeaderItems();
1144 6 : for (int i = 0; i < itemCount; ++i) {
1145 0 : readTempoMarker(info);
1146 0 : if (i < itemCount - 1) {
1147 0 : readShort();
1148 : }
1149 : }
1150 : //Dynamic section
1151 6 : itemCount = readHeaderItems();
1152 6 : for (int i = 0; i < itemCount; ++i) {
1153 0 : readDynamic();
1154 0 : if (i < itemCount - 1) {
1155 0 : readShort();
1156 : }
1157 : }
1158 : //Symbol section
1159 6 : itemCount = readHeaderItems();
1160 6 : for (int i = 0; i < itemCount; ++i) {
1161 0 : readSectionSymbol(info);
1162 0 : if (i < itemCount - 1) {
1163 0 : readShort();
1164 : }
1165 : }
1166 : //Section section
1167 6 : itemCount = readHeaderItems();
1168 12 : for (int i = 0; i < itemCount; ++i) {
1169 6 : readSection(info.getSection(i));
1170 6 : if (i < itemCount - 1) {
1171 0 : readShort();
1172 : }
1173 : }
1174 6 : }
1175 :
1176 0 : std::string crTS(int strings, int tuning[])
1177 : {
1178 : const static char* tune[] = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" };
1179 0 : std::vector<int> pitch;
1180 0 : for (int i = 0; i < strings; ++i) {
1181 0 : pitch.push_back(tuning[i]);
1182 : }
1183 0 : std::string t;
1184 0 : for (auto i : pitch) {
1185 0 : t += tune[i % 12];
1186 0 : t += " ";
1187 : }
1188 0 : return t;
1189 0 : }
1190 :
1191 3 : Measure* PowerTab::createMeasure(ptBar* bar, const Fraction& tick)
1192 : {
1193 3 : auto measure = Factory::createMeasure(score);
1194 3 : Fraction nts(bar->numerator, bar->denominator);
1195 :
1196 3 : measure->setTick(tick);
1197 3 : measure->setTimesig(nts);
1198 3 : measure->setTicks(nts);
1199 :
1200 3 : score->measures()->append(measure);
1201 :
1202 3 : return measure;
1203 : }
1204 :
1205 6 : PowerTab::ptSection& PowerTab::ptTrack::getSection(int ind)
1206 : {
1207 9 : for (int i = (int)sections.size(); i < ind + 1; ++i) {
1208 3 : sections.push_back(ptSection(i));
1209 : }
1210 6 : return sections[ind];
1211 : }
1212 :
1213 3 : PowerTab::ptSection::ptSection(int num)
1214 : {
1215 3 : number = num;
1216 3 : }
1217 :
1218 0 : PowerTab::ptPosition& PowerTab::ptSection::getPosition(int pos)
1219 : {
1220 0 : unsigned int i = 0;
1221 0 : while (i < positions.size()) {
1222 0 : auto& p = positions[i];
1223 0 : if (p.position == pos) {
1224 0 : return p;
1225 : }
1226 0 : ++i;
1227 : }
1228 0 : ptPosition p;
1229 0 : p.position = pos;
1230 0 : positions.emplace_back(p);
1231 0 : return positions.back();
1232 0 : }
1233 :
1234 0 : int PowerTab::ptSection::getNextPositionNumber()
1235 : {
1236 0 : int next = 0;
1237 0 : unsigned int k = 0;
1238 0 : while (k < positions.size()) {
1239 0 : auto p = positions[k];
1240 0 : next = std::max(next, p.position + 1);
1241 0 : ++k;
1242 0 : }
1243 0 : return next;
1244 : }
1245 :
1246 0 : void PowerTab::ptPosition::addComponent(ptComponent* c)
1247 : {
1248 0 : components.push_back(std::shared_ptr<ptComponent>(c));
1249 0 : }
1250 :
1251 : //---------------------------------------------------------
1252 : // read
1253 : //---------------------------------------------------------
1254 :
1255 3 : Err PowerTab::read()
1256 : {
1257 3 : if (!readVersion()) {
1258 0 : return Err::FileBadFormat;
1259 : }
1260 3 : ptSong song;
1261 :
1262 3 : readSongInfo(song.info);
1263 3 : readDataInstruments(song.track1);
1264 3 : staffInc = int(song.track1.infos.size());
1265 3 : lastStaffMap.clear();
1266 3 : readDataInstruments(song.track1);
1267 :
1268 3 : staves = int(song.track1.infos.size());
1269 :
1270 3 : std::vector<tBeatList> parts(staves);
1271 5 : for (int i = staffInc; i < staves; ++i) {
1272 4 : for (auto& sec : song.track1.sections) {
1273 2 : while (int(sec.beats.size()) < staves) {
1274 0 : sec.beats.push_back({});
1275 : }
1276 2 : parts[i].insert(parts[i].end(), sec.beats[i].begin(), sec.beats[i].end());
1277 2 : sec.beats[i].clear();
1278 : }
1279 : }
1280 :
1281 6 : for (auto& sec : song.track1.sections) {
1282 8 : for (int i = 0; i < staves; ++i) {
1283 5 : if (parts[i].size()) {
1284 2 : sec.beats[i].insert(sec.beats[i].begin(), parts[i].begin(), parts[i].end());
1285 2 : parts[i].clear();
1286 : }
1287 : }
1288 3 : addToScore(sec);
1289 8 : for (int i = 0; i < staves; ++i) {
1290 5 : parts[i] = sec.beats[i];
1291 : }
1292 : }
1293 :
1294 : MeasureBase* m;
1295 3 : if (!score->measures()->first()) {
1296 0 : m = Factory::createTitleVBox(score);
1297 0 : score->measures()->append(m);
1298 : } else {
1299 3 : m = score->measures()->first();
1300 3 : if (!m->isVBox()) {
1301 3 : MeasureBase* mb = Factory::createTitleVBox(score);
1302 3 : score->addMeasure(mb, m);
1303 3 : m = mb;
1304 : }
1305 : }
1306 : // create title
1307 3 : std::string name = song.info.name;
1308 3 : if (!name.empty()) {
1309 0 : Text* s = Factory::createText(m, TextStyleType::TITLE);
1310 0 : std::string valid;
1311 0 : muse::UtfCodec::replaceInvalid(name, valid);
1312 0 : s->setPlainText(String::fromStdString(valid));
1313 0 : m->add(s);
1314 0 : }
1315 3 : return Err::NoError;
1316 3 : }
1317 : } // namespace mu::iex::guitarpro
|