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 :
23 : #include "importgtp.h"
24 :
25 : #include "serialization/xmldom.h"
26 :
27 : #include "gtp/gp6dombuilder.h"
28 : #include "gtp/gpconverter.h"
29 :
30 : #include "engraving/dom/arpeggio.h"
31 : #include "engraving/dom/articulation.h"
32 : #include "engraving/dom/barline.h"
33 : #include "engraving/dom/box.h"
34 : #include "engraving/dom/bracket.h"
35 : #include "engraving/dom/bracketitem.h"
36 : #include "engraving/dom/chord.h"
37 : #include "engraving/dom/clef.h"
38 : #include "engraving/dom/dynamic.h"
39 : #include "engraving/dom/excerpt.h"
40 : #include "engraving/dom/factory.h"
41 : #include "engraving/dom/fingering.h"
42 : #include "engraving/dom/fret.h"
43 : #include "engraving/dom/glissando.h"
44 : #include "engraving/dom/hairpin.h"
45 : #include "engraving/dom/harmony.h"
46 : #include "engraving/dom/instrtemplate.h"
47 : #include "engraving/dom/keysig.h"
48 : #include "engraving/dom/lyrics.h"
49 : #include "engraving/dom/marker.h"
50 : #include "engraving/dom/masterscore.h"
51 : #include "engraving/dom/measure.h"
52 : #include "engraving/dom/measurebase.h"
53 : #include "engraving/dom/measurerepeat.h"
54 : #include "engraving/dom/note.h"
55 : #include "engraving/dom/notedot.h"
56 : #include "engraving/dom/ottava.h"
57 : #include "engraving/dom/part.h"
58 : #include "engraving/dom/rehearsalmark.h"
59 : #include "engraving/dom/rest.h"
60 : #include "engraving/dom/segment.h"
61 : #include "engraving/dom/slur.h"
62 : #include "engraving/dom/staff.h"
63 : #include "engraving/dom/stafftext.h"
64 : #include "engraving/dom/stafftype.h"
65 : #include "engraving/dom/stringdata.h"
66 : #include "engraving/dom/tempotext.h"
67 : #include "engraving/dom/text.h"
68 : #include "engraving/dom/textline.h"
69 : #include "engraving/dom/tie.h"
70 : #include "engraving/dom/timesig.h"
71 : #include "engraving/dom/tremolobar.h"
72 : #include "engraving/dom/tuplet.h"
73 : #include "engraving/dom/volta.h"
74 : #include "engraving/dom/stringtunings.h"
75 :
76 : #include "engraving/types/symid.h"
77 :
78 : #include "log.h"
79 :
80 : using namespace mu;
81 : using namespace muse;
82 : using namespace muse::io;
83 : using namespace mu::engraving;
84 :
85 : namespace mu::iex::guitarpro {
86 : const std::map<std::string, std::string> GuitarPro6::instrumentMapping = {
87 : { "2Mrcs", "maracas" },
88 : { "a-bass4", "acoustic-bass" },
89 : { "a-bass5", "acoustic-bass" },
90 : { "a-bass6", "acoustic-bass" },
91 : { "alt-c", "alto" },
92 : { "alt-s", "alto" },
93 : { "a-piano-gs", "piano" },
94 : { "a-piano-ss", "piano" },
95 : { "bass-c", "bass" },
96 : { "bass-flt-c", "bass-flute" },
97 : { "bassn", "bassoon" },
98 : { "bass-s", "bass" },
99 : { "basstuba-eb", "bass-eb-tuba" },
100 : { "bnj4", "banjo" },
101 : { "bnj5", "banjo" },
102 : { "bnj6", "banjo" },
103 : { "bongo", "bongos" },
104 : { "brthns", "baritone-horn" },
105 : { "brtn-c", "baritone" },
106 : { "brtn-s", "baritone" },
107 : { "cbs", "cabasa" },
108 : { "cello", "violoncello" },
109 : { "china", "chinese-tom-toms" },
110 : { "clrnt-a", "a-clarinet" },
111 : { "clrnt-bb-bass", "bass-clarinet" },
112 : { "clrnt-bb", "bb-clarinet" },
113 : { "clrnt-c", "c-clarinet" },
114 : { "clrnt-d", "d-clarinet" },
115 : { "clrnt-eb", "eb-clarinet" },
116 : { "clrnt", "clarinet" },
117 : { "clst-gs", "celesta" },
118 : { "clst-ss", "celesta" },
119 : { "clvs", "claves" },
120 : { "cngKit", "congas" },
121 : { "conga", "congas" },
122 : { "cowbell", "cowbell" },
123 : { "crash", "crash-cymbal" },
124 : { "cstnt", "castanets" },
125 : { "ctbassn", "contrabassoon" },
126 : { "ctbass", "contrabass" },
127 : { "cuicaKit", "cuica" },
128 : { "cuica", "cuica" },
129 : { "drmkt", "drumset" },
130 : { "e-bass4", "bass-guitar" },
131 : { "e-bass5", "bass-guitar" },
132 : { "e-bass6", "bass-guitar" },
133 : { "e-gtr12", "electric-guitar-treble-clef" },
134 : { "e-gtr6", "electric-guitar-treble-clef" },
135 : { "e-gtr7", "electric-guitar-treble-clef" },
136 : { "e-gtr8", "electric-guitar-treble-clef" },
137 : { "em-organ-gs", "organ" },
138 : { "em-organ-ss", "organ" },
139 : { "en-horn", "english-horn" },
140 : { "e-piano-gs", "electric-piano" },
141 : { "e-piano-ss", "electric-piano" },
142 : { "flt-c", "flute" },
143 : { "flt-g", "alto-flute" },
144 : { "flt-whstl", "tin-whistle" },
145 : { "fr-horn", "horn" },
146 : { "grcss", "bass-drum" }, //grancassa is an alternative name for bass drum
147 : { "guiro", "guiro" },
148 : { "harp-gs", "harp" },
149 : { "harp-ss", "harp" },
150 : { "hclap", "hand-clap" },
151 : { "hihat", "hi-hat" },
152 : { "hrpch-gs", "harpsichord" },
153 : { "hrpch-ss", "harpsichord" },
154 : { "jngl-bell", "sleigh-bells" },
155 : { "klmb", "kalimba" },
156 : { "mrcs", "maracas" },
157 : { "n-gtr6", "guitar-nylon-treble-clef" },
158 : { "n-gtr7", "guitar-nylon-treble-clef" },
159 : { "n-gtr8", "guitar-nylon-treble-clef" },
160 : { "oboe", "oboe" },
161 : { "ocrn", "ocarina" },
162 : { "pccl", "piccolo" },
163 : { "pedalhihat", "hi-hat" },
164 : { "pnflt", "pan-flute" },
165 : { "ptt", "cymbal" }, //piatti is cymbal in italian
166 : { "rec", "recorder" },
167 : { "ride", "ride-cymbal" },
168 : { "rvs-cymb", "cymbal" },
169 : { "sax-alt-eb", "alto-saxophone" },
170 : { "sax-bar-eb", "baritone-saxophone" },
171 : { "sax-bass-eb", "bass-saxophone" },
172 : { "sax-ms-f", "mezzo-soprano-saxophone" },
173 : { "sax-sop-bb", "soprano-saxophone" },
174 : { "sax-ten-bb", "tenor-saxophone" },
175 : { "sax-ten-c", "melody-saxophone" },
176 : { "s-bass4", "electric-bass" },
177 : { "s-bass5", "5-string-electric-bass" },
178 : { "s-gtr12", "guitar-steel-treble-clef" },
179 : { "s-gtr6", "guitar-steel-treble-clef" },
180 : { "s-gtr7", "guitar-steel-treble-clef" },
181 : { "s-gtr8", "guitar-steel-treble-clef" },
182 : { "shkr", "percussion" },
183 : { "shmsn", "shamisen" },
184 : { "shn", "sheng" },
185 : { "snare", "snare-drum" },
186 : { "snr", "snare-drum" },
187 : { "snt-brass-gs", "brass-synthesizer" },
188 : { "snt-brass-ss", "brass-synthesizer" },
189 : //{"snt-key-gs", ""},
190 : //{"snt-key-ss", ""},
191 : //{"snt-seq-gs", ""},
192 : //{"snt-seq-ss", ""},
193 : { "snt-lead-gs", "poly-synth" },
194 : { "snt-lead-ss", "poly-synth" },
195 : { "snt-pad", "pad-synth" },
196 : { "snt-pad-gs", "pad-synth" },
197 : { "snt-pad-ss", "pad-synth" },
198 : { "splash", "splash-cymbal" },
199 : { "sprn-c", "soprano" },
200 : { "sprn-s", "soprano" },
201 : { "tmbrn", "tambourine" }, // to be mapped
202 : { "Tambourine-Perc", "tambourine" },
203 : { "Tambourine", "tambourine" },
204 : { "tmblKit", "timbales" },
205 : { "tmbl", "timbales" },
206 : { "tmpn", "timpani" },
207 : { "tnklbll", "tubular-bells" }, //The short form does not match but this is very likely due to the description
208 : { "tnr-c", "tenor" },
209 : { "tnr-s", "tenor" },
210 : { "Triangle-Percu", "triangle" },
211 : { "trmbn-bb-bass", "bass-trombone" },
212 : { "trmbn-bb", "tenor-trombone" },
213 : { "trmbn-bb-treble", "trombone-treble" },
214 : { "trmbn-eb", "alto-trombone" },
215 : { "trmpt-a", "a-trumpet" },
216 : { "trmpt-bb", "bb-trumpet" },
217 : { "trmpt-c-bass", "c-bass-trumpet" },
218 : { "trmpt-c", "c-trumpet" },
219 : { "trmpt-d", "d-trumpet" },
220 : { "trmpt-eb-bass", "eb-bass-trumpet" },
221 : { "trmpt-eb", "eb-trumpet" },
222 : { "trmpt-e", "e-trumpet" },
223 : { "trmpt-f", "f-trumpet" },
224 : { "trmpt-flgh", "flugelhorn" },
225 : { "trngl", "triangle" },
226 : { "ukll4", "ukulele" },
227 : { "vbrphn", "vibraphone" },
228 : { "vbrslp", "vibraslap" }, // to be mapped
229 : { "vla", "viola" },
230 : { "vln", "violin" },
231 : { "wdblckKit", "wood-blocks" },
232 : { "wdblck", "wood-blocks" },
233 : { "whstlKit", "slide-whistle" },
234 : { "whstl", "tin-whistle" },
235 : { "xlphn", "xylophone" }
236 : };
237 :
238 76 : std::unique_ptr<IGPDomBuilder> GuitarPro6::createGPDomBuilder() const
239 : {
240 76 : return std::make_unique<GP6DomBuilder>();
241 : }
242 :
243 : //---------------------------------------------------------
244 : // readBit
245 : //---------------------------------------------------------
246 :
247 43939534 : int GuitarPro6::readBit(ByteArray* buffer)
248 : {
249 : // calculate the byte index by dividing the position in bits by the bits per byte
250 43939534 : size_t byteIndex = position / BITS_IN_BYTE;
251 :
252 : // calculate our offset so we know how much to bit shift
253 43939534 : int byteOffset = ((BITS_IN_BYTE - 1) - (position % BITS_IN_BYTE));
254 :
255 : // calculate the bit which we want to read
256 43939534 : char byte = (byteIndex < buffer->size()) ? (*buffer)[byteIndex] : char(0);
257 43939534 : int bit = (((byte & 0xff) >> byteOffset) & 0x01);
258 :
259 : // increment our current position so we know this bit has been read
260 43939534 : position++;
261 43939534 : return bit; // return the bit we calculated
262 : }
263 :
264 : //---------------------------------------------------------
265 : // readBits
266 : //---------------------------------------------------------
267 :
268 12791590 : int GuitarPro6::readBits(ByteArray* buffer, int bitsToRead)
269 : {
270 12791590 : int bits = 0;
271 31483764 : for (int i = (bitsToRead - 1); i >= 0; i--) {
272 18692174 : bits |= (readBit(buffer) << i);
273 : }
274 12791590 : return bits;
275 : }
276 :
277 : //---------------------------------------------------------
278 : // readBitsReversed
279 : //---------------------------------------------------------
280 :
281 12000258 : int GuitarPro6::readBitsReversed(ByteArray* buffer, int bitsToRead)
282 : {
283 12000258 : int bits = 0;
284 37247618 : for (int i = 0; i < bitsToRead; i++) {
285 25247360 : bits |= readBit(buffer) << i;
286 : }
287 12000258 : return bits;
288 : }
289 :
290 : //---------------------------------------------------------
291 : // getBytes
292 : //---------------------------------------------------------
293 :
294 1113 : ByteArray GuitarPro6::getBytes(ByteArray* buffer, int offset, int length)
295 : {
296 1113 : ByteArray newBytes;
297 : // compute new bytes from our buffer and return byte array
298 4836382 : for (int i = 0; i < length; i++) {
299 4835269 : if (static_cast<int>(buffer->size()) > offset + i) {
300 4835260 : newBytes.insert(i, ((*buffer)[offset + i]));
301 : }
302 : }
303 1113 : return newBytes;
304 0 : }
305 :
306 : //---------------------------------------------------------
307 : // readInteger
308 : //---------------------------------------------------------
309 :
310 2175 : int GuitarPro6::readInteger(ByteArray* buffer, int offset)
311 : {
312 : // assign four bytes and take them from the buffer
313 : char bytes[4];
314 2175 : bytes[0] = (*buffer)[offset + 0];
315 2175 : bytes[1] = (*buffer)[offset + 1];
316 2175 : bytes[2] = (*buffer)[offset + 2];
317 2175 : bytes[3] = (*buffer)[offset + 3];
318 : // increment positioning so we keep track of where we are
319 2175 : position += sizeof(int) * BITS_IN_BYTE;
320 : // bit shift in order to compute our integer value and return
321 2175 : return ((bytes[3] & 0xff) << 24) | ((bytes[2] & 0xff) << 16) | ((bytes[1] & 0xff) << 8) | (bytes[0] & 0xff);
322 : }
323 :
324 : //---------------------------------------------------------
325 : // readString
326 : //---------------------------------------------------------
327 :
328 379 : ByteArray GuitarPro6::readString(ByteArray* buffer, int offset, int length)
329 : {
330 379 : ByteArray filename;
331 : // compute the string by iterating through the buffer
332 5691 : for (int i = 0; i < length; i++) {
333 5691 : int charValue = (((*buffer)[offset + i]) & 0xff);
334 5691 : if (charValue == 0) {
335 379 : break;
336 : }
337 5312 : filename.push_back((char)charValue);
338 : }
339 379 : return filename;
340 0 : }
341 :
342 : //---------------------------------------------------------
343 : // unhandledNode
344 : //---------------------------------------------------------
345 :
346 0 : void GuitarPro6::unhandledNode(String nodeName)
347 : {
348 0 : LOGD() << "WARNING: Discovered unhandled node name" << nodeName;
349 0 : }
350 :
351 : //---------------------------------------------------------
352 : // getNode
353 : //---------------------------------------------------------
354 :
355 0 : XmlDomNode GuitarPro6::getNode(const String& id, XmlDomNode currentDomNode)
356 : {
357 0 : while (!(currentDomNode).isNull()) {
358 0 : String currentId = currentDomNode.toElement().attribute("id").value();
359 0 : if (currentId == id) {
360 0 : return currentDomNode;
361 : }
362 0 : currentDomNode = currentDomNode.nextSibling();
363 0 : }
364 0 : LOGD() << "WARNING: A null node was returned when search for the identifier" << id << ". Your Guitar Pro file may be corrupted.";
365 0 : return currentDomNode;
366 : }
367 :
368 : //---------------------------------------------------------
369 : // readGpif
370 : //---------------------------------------------------------
371 :
372 221 : void GuitarPro6::readGpif(ByteArray* data)
373 : {
374 221 : XmlDomDocument domDoc;
375 221 : domDoc.setContent(*data);
376 221 : XmlDomElement domElem = domDoc.rootElement();
377 :
378 221 : auto builder = createGPDomBuilder();
379 221 : builder->buildGPDomModel(&domElem);
380 :
381 221 : GPConverter scoreBuilder(score, builder->getGPDomModel(), iocContext());
382 221 : scoreBuilder.convertGP();
383 221 : }
384 :
385 : //---------------------------------------------------------
386 : // parseFile
387 : //---------------------------------------------------------
388 :
389 379 : void GuitarPro6::parseFile(const char* filename, ByteArray* data)
390 : {
391 : // test to check if we are dealing with the score
392 379 : if (!strcmp(filename, "score.gpif")) {
393 76 : readGpif(data);
394 : }
395 379 : }
396 :
397 : //---------------------------------------------------------
398 : // readGPX
399 : //---------------------------------------------------------
400 :
401 152 : void GuitarPro6::readGPX(ByteArray* buffer)
402 : {
403 : // start by reading the file header. It will tell us if the byte array is compressed.
404 152 : int fileHeader = readInteger(buffer, 0);
405 :
406 152 : if (fileHeader == GPX_HEADER_COMPRESSED) {
407 : // this is a compressed file.
408 76 : int length = readInteger(buffer, position / BITS_IN_BYTE);
409 76 : ByteArray bcfsBuffer;
410 76 : bcfsBuffer.reserve(length);
411 76 : int positionCounter = 0;
412 11879914 : while ((position / BITS_IN_BYTE) < length) {
413 : // read the bit indicating compression information
414 11879838 : int flag = readBits(buffer, 1);
415 :
416 11879838 : if (flag) {
417 120420 : int bits = readBits(buffer, 4);
418 120420 : int offs = readBitsReversed(buffer, bits);
419 120420 : int size = readBitsReversed(buffer, bits);
420 :
421 120420 : int pos = (static_cast<int>(bcfsBuffer.size()) - offs);
422 4822171 : for (int i = 0; i < (size > offs ? offs : size); i++) {
423 4701751 : bcfsBuffer.insert(positionCounter, bcfsBuffer[pos + i]);
424 4701751 : positionCounter++;
425 : }
426 : } else {
427 11759418 : int size = readBitsReversed(buffer, 2);
428 12550750 : for (int i = 0; i < size; i++) {
429 791332 : bcfsBuffer.insert(positionCounter, readBits(buffer, 8));
430 791332 : positionCounter++;
431 : }
432 : }
433 : }
434 : // recurse on the decompressed file stored as a byte array
435 76 : readGPX(&bcfsBuffer);
436 152 : } else if (fileHeader == GPX_HEADER_UNCOMPRESSED) {
437 : // this is an uncompressed file - strip the header off
438 76 : *buffer = buffer->right(buffer->size() - sizeof(int));
439 76 : size_t sectorSize = 0x1000;
440 76 : int offset = 0;
441 607 : while ((offset = (offset + static_cast<int>(sectorSize))) + 3 < static_cast<int>(buffer->size())) {
442 455 : int newInt = readInteger(buffer, offset);
443 455 : if (newInt == 2) {
444 379 : int indexFileName = (offset + 4);
445 379 : int indexFileSize = (offset + 0x8C);
446 379 : int indexOfBlock = (offset + 0x94);
447 :
448 : // create a byte array and put information about files found in it
449 379 : int block = 0;
450 379 : int blockCount = 0;
451 379 : ByteArray* fileBytes = new ByteArray();
452 1113 : while ((block = (readInteger(buffer, (indexOfBlock + (4 * (blockCount++)))))) != 0) {
453 734 : fileBytes->push_back(getBytes(buffer, (offset = (block * static_cast<int>(sectorSize))), static_cast<int>(sectorSize)));
454 : }
455 : // get file information and read the file
456 379 : size_t fileSize = readInteger(buffer, indexFileSize);
457 379 : if (fileBytes->size() >= fileSize) {
458 379 : ByteArray filenameBytes = readString(buffer, indexFileName, 127);
459 379 : const char* filename = filenameBytes.constChar();
460 379 : ByteArray data = getBytes(fileBytes, 0, static_cast<int>(fileSize));
461 379 : parseFile(filename, &data);
462 379 : }
463 379 : delete fileBytes;
464 : }
465 : }
466 : }
467 152 : }
468 :
469 : //---------------------------------------------------------
470 : // read
471 : //---------------------------------------------------------
472 :
473 76 : bool GuitarPro6::read(IODevice* io)
474 : {
475 76 : f = io;
476 76 : previousTempo = -1;
477 : // decompress and read files contained within GPX file
478 76 : ByteArray ba = io->readAll();
479 :
480 76 : readGPX(&ba);
481 :
482 76 : return true;
483 76 : }
484 : } // namespace mu::iex::guitarpro
|