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 <limits>
24 :
25 : #include <QFile>
26 : #include <QFileInfo>
27 :
28 : #include "bb.h"
29 :
30 : #include "engraving/dom/box.h"
31 : #include "engraving/dom/chord.h"
32 : #include "engraving/dom/chordlist.h"
33 : #include "engraving/dom/drumset.h"
34 : #include "engraving/dom/factory.h"
35 : #include "engraving/dom/harmony.h"
36 : #include "engraving/dom/key.h"
37 : #include "engraving/dom/keysig.h"
38 : #include "engraving/dom/layoutbreak.h"
39 : #include "engraving/dom/masterscore.h"
40 : #include "engraving/dom/measure.h"
41 : #include "engraving/dom/mscore.h"
42 : #include "engraving/dom/note.h"
43 : #include "engraving/dom/part.h"
44 : #include "engraving/dom/pitchspelling.h"
45 : #include "engraving/dom/rest.h"
46 : #include "engraving/dom/segment.h"
47 : #include "engraving/dom/slur.h"
48 : #include "engraving/dom/staff.h"
49 : #include "engraving/dom/text.h"
50 : #include "engraving/dom/tie.h"
51 : #include "engraving/dom/utils.h"
52 : #include "engraving/editing/editenharmonicspelling.h"
53 : #include "engraving/editing/transpose.h"
54 : #include "engraving/engravingerrors.h"
55 :
56 : #include "log.h"
57 :
58 : using namespace mu::engraving;
59 :
60 : namespace mu::iex::bb {
61 : //---------------------------------------------------------
62 : // BBTrack
63 : //---------------------------------------------------------
64 :
65 2 : BBTrack::BBTrack(BBFile* f)
66 : {
67 2 : bb = f;
68 2 : _outChannel = -1;
69 2 : _drumTrack = false;
70 2 : }
71 :
72 0 : BBTrack::~BBTrack()
73 : {
74 0 : }
75 :
76 : //---------------------------------------------------------
77 : // MNote
78 : // special Midi Note
79 : //---------------------------------------------------------
80 :
81 : struct MNote {
82 : Event mc;
83 : QList<Tie*> ties;
84 :
85 0 : MNote(const Event& _mc)
86 0 : : mc(_mc)
87 : {
88 0 : for (size_t i = 0; i < mc.notes().size(); ++i) {
89 0 : ties.append(0);
90 : }
91 0 : }
92 : };
93 :
94 : //---------------------------------------------------------
95 : // BBFile
96 : //---------------------------------------------------------
97 :
98 1983 : BBFile::BBFile()
99 : {
100 507648 : for (int i = 0; i < MAX_BARS; ++i) {
101 505665 : _barType[i] = 0;
102 : }
103 1983 : bbDivision = 120;
104 1983 : }
105 :
106 : //---------------------------------------------------------
107 : // BBFile
108 : //---------------------------------------------------------
109 :
110 1983 : BBFile::~BBFile()
111 : {
112 1983 : }
113 :
114 : //---------------------------------------------------------
115 : // read
116 : // return false on error
117 : //---------------------------------------------------------
118 :
119 1983 : bool BBFile::read(const QString& name)
120 : {
121 1983 : _siglist.clear();
122 1983 : _siglist.add(0, Fraction(4, 4)); // debug
123 :
124 1983 : _path = name;
125 1983 : QFile f(name);
126 1983 : if (!f.open(QIODevice::ReadOnly)) {
127 0 : return false;
128 : }
129 1983 : ba = f.readAll();
130 1983 : f.close();
131 :
132 1983 : a = (const unsigned char*)ba.data();
133 1983 : size = ba.size();
134 :
135 : //---------------------------------------------------
136 : // read version
137 : //---------------------------------------------------
138 :
139 1983 : int idx = 0;
140 1983 : if (!checkRange(idx, 1)) {
141 1 : LOGE() << "BB: truncated file (version)";
142 1 : return false;
143 : }
144 1982 : _version = a[idx++];
145 1982 : switch (_version) {
146 1982 : case 0x43:
147 : case 0x44:
148 : case 0x45:
149 : case 0x46:
150 : case 0x47:
151 : case 0x48:
152 : case 0x49:
153 1982 : break;
154 0 : default:
155 0 : LOGD("BB: unknown file version %02x", _version);
156 0 : return false;
157 : }
158 :
159 1982 : LOGD("read <%s> version 0x%02x", qPrintable(name), _version);
160 :
161 : //---------------------------------------------------
162 : // read title
163 : //---------------------------------------------------
164 :
165 1982 : if (!checkRange(idx, 1)) {
166 1 : LOGE() << "BB: truncated file (title length)";
167 1 : return false;
168 : }
169 1981 : int len = a[idx++];
170 1981 : if (!checkRange(idx, len)) {
171 11 : LOGE() << "BB: truncated file (title)";
172 11 : return false;
173 : }
174 1970 : _title = new char[len + 1];
175 23640 : for (int i = 0; i < len; ++i) {
176 21670 : _title[i] = a[idx++];
177 : }
178 1970 : _title[len] = 0;
179 :
180 : //---------------------------------------------------
181 : // read style(timesig), key and bpm
182 : //---------------------------------------------------
183 :
184 1970 : if (!checkRange(idx, 3)) {
185 3 : LOGE() << "BB: truncated file (style)";
186 3 : return false;
187 : }
188 1967 : ++idx;
189 1967 : ++idx;
190 1967 : _style = a[idx++] - 1;
191 1967 : if (_style < 0 || _style >= int(sizeof(styles) / sizeof(*styles))) {
192 0 : LOGD("Import bb: unknown style %d", _style + 1);
193 0 : return false;
194 : }
195 1967 : if (!checkRange(idx, 1)) {
196 1 : LOGE() << "BB: truncated file (key)";
197 1 : return false;
198 : }
199 1966 : _key = a[idx++];
200 :
201 : // map D# G# A# to Eb Ab Db
202 : // major C, Db, D, Eb, E, F, Gb, G, Ab, A, Bb, B, C#, D#, F#, G#, A#
203 : // minor C, Db, D, Eb, E, F, Gb, G, Ab, A, Bb, B, C#, D#, F#, G#, A#
204 : static int kt[] = {
205 : 0, 0, -5, 2, -3, 4, -1, -6, 1, -4, 3, -2, 5, 7, -3, 6, -4, -2,
206 : -3, 4, -1, -6, 1, -4, 3, -2, 5, 0, -5, 2, 4, 6, 3, 5, 7
207 : };
208 1966 : if (_key >= int(sizeof(kt) / sizeof(*kt))) {
209 0 : LOGD("bad key %d", _key);
210 0 : return false;
211 : }
212 1966 : _key = kt[_key];
213 :
214 1966 : if (!checkRange(idx, 2)) {
215 2 : LOGE() << "BB: truncated file (bpm)";
216 2 : return false;
217 : }
218 1964 : _bpm = a[idx] + (a[idx + 1] << 8);
219 1964 : idx += 2;
220 :
221 1964 : LOGD("Title <%s>", _title);
222 1964 : LOGD("style %d", _style);
223 1964 : LOGD("key %d", _key);
224 1964 : LOGD("sig %d/%d", timesigZ(), timesigN());
225 1964 : LOGD("bpm %d", _bpm);
226 :
227 : //---------------------------------------------------
228 : // read bar types
229 : //---------------------------------------------------
230 :
231 1964 : if (!checkRange(idx, 1)) {
232 1 : LOGE() << "BB: truncated file (bar start)";
233 1 : return false;
234 : }
235 1963 : int bar = a[idx++]; // starting bar number
236 13711 : while (bar < 255) {
237 11757 : if (!checkRange(idx, 1)) {
238 6 : LOGE() << "BB: truncated file (bar type)";
239 6 : return false;
240 : }
241 11751 : int val = a[idx++];
242 11751 : if (val == 0) {
243 5874 : if (!checkRange(idx, 1)) {
244 3 : LOGE() << "BB: truncated file (bar run-length)";
245 3 : return false;
246 : }
247 5871 : bar += a[idx++];
248 : } else {
249 5877 : LOGD("bar type: bar %d val %d", bar, val);
250 5877 : _barType[bar++] = val;
251 : }
252 : }
253 :
254 : //---------------------------------------------------
255 : // read chord extensions
256 : //---------------------------------------------------
257 :
258 : int beat;
259 187996 : for (beat = 0; beat < MAX_BARS * 4;) {
260 186192 : if (!checkRange(idx, 1)) {
261 99 : LOGE() << "BB: truncated file (chord extension)";
262 99 : return false;
263 : }
264 186093 : int val = a[idx++];
265 186093 : if (val == 0) {
266 95734 : if (!checkRange(idx, 1)) {
267 51 : LOGE() << "BB: truncated file (chord ext run-length)";
268 51 : return false;
269 : }
270 95683 : beat += a[idx++];
271 : } else {
272 90359 : BBChord c;
273 90359 : c.extension = val;
274 90359 : c.beat = beat * (timesigZ() / timesigN());
275 90359 : ++beat;
276 90359 : _chords.append(c);
277 : }
278 : }
279 :
280 : //---------------------------------------------------
281 : // read chord root
282 : //---------------------------------------------------
283 :
284 1804 : int roots = 0;
285 1804 : int maxbeat = 0;
286 172991 : for (beat = 0; beat < MAX_BARS * 4;) {
287 171338 : if (!checkRange(idx, 1)) {
288 99 : LOGE() << "BB: truncated file (chord root)";
289 99 : return false;
290 : }
291 171239 : int val = a[idx++];
292 171239 : if (val == 0) {
293 88079 : if (!checkRange(idx, 1)) {
294 51 : LOGE() << "BB: truncated file (chord root run-length)";
295 51 : return false;
296 : }
297 88028 : beat += a[idx++];
298 : } else {
299 83160 : int root = val % 18;
300 83160 : int bass = (root - 1 + val / 18) % 18 + 1;
301 83160 : if (root == bass) {
302 83158 : bass = 0;
303 : }
304 83160 : int ibeat = beat * (timesigZ() / timesigN());
305 83160 : if (roots >= _chords.size()) {
306 1 : LOGE() << "BB: chord root/extension count mismatch";
307 1 : return false;
308 : }
309 83159 : if (ibeat != _chords[roots].beat) {
310 0 : LOGD("import bb: inconsistent chord type and root beat");
311 0 : return false;
312 : }
313 83159 : _chords[roots].root = root;
314 83159 : _chords[roots].bass = bass;
315 83159 : if (maxbeat < beat) {
316 81356 : maxbeat = beat;
317 : }
318 83159 : ++roots;
319 83159 : ++beat;
320 : }
321 : }
322 :
323 1653 : _measures = ((maxbeat + timesigZ() - 1) / timesigZ()) + 1;
324 :
325 1653 : if (roots != _chords.size()) {
326 0 : LOGD("import bb: roots %d != extensions %lld", roots, _chords.size());
327 0 : return false;
328 : }
329 1653 : LOGD("Measures %d", _measures);
330 :
331 1653 : if (!checkRange(idx, 1)) {
332 1 : LOGE() << "BB: truncated file (chorus marker)";
333 1 : return false;
334 : }
335 1652 : if (a[idx] == 1) { //??
336 1652 : LOGD("Skip 0x%02x at 0x%04x", a[idx], idx);
337 1652 : ++idx;
338 : }
339 :
340 1652 : if (!checkRange(idx, 3)) {
341 3 : LOGE() << "BB: truncated file (chorus/repeats)";
342 3 : return false;
343 : }
344 1649 : _startChorus = a[idx++];
345 1649 : _endChorus = a[idx++];
346 1649 : _repeats = a[idx++];
347 :
348 1649 : LOGD("start chorus %d end chorus %d repeats %d, pos now 0x%x",
349 : _startChorus, _endChorus, _repeats, idx);
350 :
351 1649 : if (_startChorus >= _endChorus) {
352 1649 : _startChorus = 0;
353 1649 : _endChorus = 0;
354 1649 : _repeats = 1;
355 : }
356 :
357 : //---------------------------------------------------
358 : // read style file
359 : //---------------------------------------------------
360 :
361 1649 : bool found = false;
362 103586 : for (int i = idx; i < size; ++i) {
363 103511 : if (a[i] == 0x42) {
364 1585 : if (checkRange(i, 2) && a[i + 1] < 16) {
365 11049 : for (int k = i + 2; k < (i + 18); ++k) {
366 11049 : if (!checkRange(k, 4)) {
367 10 : break;
368 : }
369 11039 : if (a[k] == '.' && a[k + 1] == 'S' && a[k + 2] == 'T' && a[k + 3] == 'Y') {
370 1574 : found = true;
371 1574 : break;
372 : }
373 : }
374 : }
375 1585 : if (found) {
376 1574 : idx = i + 1;
377 1574 : break;
378 : }
379 : }
380 : }
381 1649 : if (!found) {
382 75 : LOGD("import bb: style file not found");
383 75 : return false;
384 : }
385 :
386 1574 : LOGD("read styleName at 0x%x", idx);
387 1574 : if (!checkRange(idx, 1)) {
388 0 : LOGE() << "BB: truncated file (style name length)";
389 0 : return false;
390 : }
391 1574 : len = a[idx++];
392 1574 : if (!checkRange(idx, len)) {
393 0 : LOGE() << "BB: truncated file (style name)";
394 0 : return false;
395 : }
396 1574 : _styleName = new char[len + 1];
397 :
398 17314 : for (int i = 0; i < len; ++i) {
399 15740 : _styleName[i] = a[idx++];
400 : }
401 1574 : _styleName[len] = 0;
402 :
403 1574 : LOGD("style name <%s>", _styleName);
404 :
405 : // read midi events
406 1574 : if (!checkRange(size - 4, 4)) {
407 0 : LOGE() << "BB: truncated file (event header)";
408 0 : return false;
409 : }
410 1574 : int eventStart = a[size - 4] + a[size - 3] * 256;
411 1574 : int eventCount = a[size - 2] + a[size - 1] * 256;
412 :
413 1574 : const int EVENT_END_BOUNDARY = size - 4;
414 :
415 1574 : Fraction endTick = Fraction::fromTicks(_measures * bbDivision * 4 * timesigZ() / timesigN());
416 :
417 1574 : if (eventCount == 0) {
418 1414 : LOGD("no melody");
419 1414 : return true;
420 : } else {
421 160 : idx = eventStart;
422 160 : LOGD("melody found at 0x%x", idx);
423 160 : int i = 0;
424 160 : int lastLen = 0;
425 164 : for (i = 0; i < eventCount; ++i, idx+=12) {
426 162 : if (idx + 12 > EVENT_END_BOUNDARY) {
427 76 : LOGE() << "Event out of range";
428 76 : return false;
429 : }
430 86 : int type = a[idx + 4] & 0xf0;
431 86 : if (type == 0x90) {
432 4 : int channel = a[idx + 7];
433 4 : BBTrack* track = 0;
434 4 : foreach (BBTrack* t, _tracks) {
435 2 : if (t->outChannel() == channel) {
436 2 : track = t;
437 2 : break;
438 : }
439 4 : }
440 4 : if (track == 0) {
441 2 : track = new BBTrack(this);
442 2 : track->setOutChannel(channel);
443 2 : _tracks.append(track);
444 : }
445 4 : uint32_t rawTick = uint32_t(a[idx]) + (uint32_t(a[idx + 1]) << 8) + (uint32_t(a[idx + 2]) << 16)
446 4 : + (uint32_t(a[idx + 3]) << 24);
447 4 : if (rawTick > uint32_t(std::numeric_limits<int>::max())) {
448 1 : LOGD("note event tick out of range at idx %04x", idx);
449 2 : continue;
450 : }
451 3 : Fraction tick = Fraction::fromTicks(int(rawTick));
452 3 : tick -= Fraction::fromTicks(4 * bbDivision);
453 3 : if (tick >= endTick) {
454 0 : LOGD("event tick %d > %d", tick.ticks(), endTick.ticks());
455 0 : continue;
456 : }
457 3 : Event note(ME_NOTE);
458 3 : note.setOntime((tick.ticks() * Constants::DIVISION) / bbDivision);
459 3 : note.setPitch(a[idx + 5]);
460 3 : note.setVelo(a[idx + 6]);
461 3 : note.setChannel(channel);
462 3 : uint32_t rawLen = uint32_t(a[idx + 8]) + (uint32_t(a[idx + 9]) << 8) + (uint32_t(a[idx + 10]) << 16)
463 3 : + (uint32_t(a[idx + 11]) << 24);
464 3 : if (rawLen > uint32_t(std::numeric_limits<int>::max())) {
465 1 : LOGD("note event length out of range at idx %04x", idx);
466 1 : continue;
467 : }
468 2 : int len1 = int(rawLen);
469 2 : if (len1 == 0) {
470 0 : if (lastLen == 0) {
471 0 : LOGD("note event of len 0 at idx %04x", idx);
472 0 : continue;
473 : }
474 0 : len1 = lastLen;
475 : }
476 2 : lastLen = len1;
477 2 : note.setDuration(int((uint64_t(len1) * Constants::DIVISION) / bbDivision));
478 2 : track->append(note);
479 85 : } else if (type == 0xb0 || type == 0xc0) {
480 : // ignore controller
481 82 : } else if (type == 0) {
482 74 : break;
483 : } else {
484 8 : LOGD("unknown event type 0x%02x at x%04x", a[idx + 4], idx);
485 8 : break;
486 : }
487 : }
488 84 : LOGD("Events found x%02x (%d)", i, i);
489 : }
490 84 : return true;
491 1983 : }
492 :
493 : //---------------------------------------------------------
494 : // importBB
495 : //---------------------------------------------------------
496 :
497 6 : Err importBB(MasterScore* score, const QString& name)
498 : {
499 6 : BBFile bb;
500 6 : if (!QFileInfo::exists(name)) {
501 0 : return engraving::Err::FileNotFound;
502 : }
503 6 : if (!bb.read(name)) {
504 2 : LOGD("Cannot open file <%s>", qPrintable(name));
505 2 : return engraving::Err::FileOpenError;
506 : }
507 4 : score->style().set(Sid::chordsXmlFile, true);
508 4 : score->chordList()->read(u"chords.xml");
509 4 : *(score->sigmap()) = bb.siglist();
510 :
511 4 : QList<BBTrack*>* tracks = bb.tracks();
512 4 : int ntracks = tracks->size();
513 4 : if (ntracks == 0) { // no events?
514 4 : ntracks = 1;
515 : }
516 8 : for (int i = 0; i < ntracks; ++i) {
517 4 : Part* part = new Part(score);
518 4 : Staff* s = Factory::createStaff(part);
519 4 : score->appendStaff(s);
520 4 : score->appendPart(part);
521 : }
522 :
523 : //---------------------------------------------------
524 : // create measures
525 : //---------------------------------------------------
526 :
527 196 : for (int i = 0; i < bb.measures(); ++i) {
528 192 : Measure* measure = Factory::createMeasure(score);
529 192 : Fraction tick = Fraction::fromTicks(score->sigmap()->bar2tick(i, 0));
530 192 : measure->setTick(tick);
531 192 : Fraction ts = score->sigmap()->timesig(tick.ticks()).timesig();
532 192 : measure->setTimesig(ts);
533 192 : measure->setTicks(ts);
534 192 : score->measures()->append(measure);
535 : }
536 :
537 : //---------------------------------------------------
538 : // create notes
539 : //---------------------------------------------------
540 :
541 4 : foreach (BBTrack* track, * tracks) {
542 0 : track->cleanup();
543 4 : }
544 :
545 4 : if (tracks->isEmpty()) {
546 196 : for (MeasureBase* mb = score->first(); mb; mb = mb->next()) {
547 192 : if (!mb->isMeasure()) {
548 0 : continue;
549 : }
550 192 : Measure* measure = (Measure*)mb;
551 192 : Segment* s = measure->getSegment(SegmentType::ChordRest, measure->tick());
552 192 : Rest* rest = Factory::createRest(s, TDuration(DurationType::V_MEASURE));
553 192 : rest->setTicks(measure->ticks());
554 192 : rest->setTrack(0);
555 192 : s->add(rest);
556 : }
557 : } else {
558 0 : int staffIdx = 0;
559 0 : foreach (BBTrack* track, * tracks) {
560 0 : bb.convertTrack(score, track, staffIdx++);
561 0 : }
562 : }
563 :
564 196 : for (MeasureBase* mb = score->first(); mb; mb = mb->next()) {
565 192 : if (!mb->isMeasure()) {
566 0 : continue;
567 : }
568 192 : Measure* measure = (Measure*)mb;
569 192 : Segment* s = measure->findSegment(SegmentType::ChordRest, measure->tick());
570 192 : if (s == 0) {
571 0 : Rest* rest = Factory::createRest(s, TDuration(DurationType::V_MEASURE));
572 0 : rest->setTicks(measure->ticks());
573 0 : rest->setTrack(0);
574 0 : Segment* s1 = measure->getSegment(SegmentType::ChordRest, measure->tick());
575 0 : s1->add(rest);
576 : }
577 : }
578 :
579 4 : EditEnharmonicSpelling::spell(score);
580 :
581 : //---------------------------------------------------
582 : // create title
583 : //---------------------------------------------------
584 :
585 4 : MeasureBase* measureB = score->first();
586 4 : Text* text = Factory::createText(measureB, TextStyleType::TITLE);
587 4 : text->setPlainText(String::fromUtf8(bb.title()));
588 :
589 4 : if (!measureB->isVBox()) {
590 4 : measureB = Factory::createTitleVBox(score);
591 4 : measureB->setNext(score->first());
592 4 : score->measures()->add(measureB);
593 : }
594 4 : measureB->add(text);
595 :
596 : //---------------------------------------------------
597 : // create chord symbols
598 : //---------------------------------------------------
599 :
600 : static const std::array<int, 17> table = {
601 : //C Db, D, Eb, E, F, Gb, G, Ab, A, Bb, B, C#, D#, F# G# A#
602 : 14, 9, 16, 11, 18, 13, 8, 15, 10, 17, 12, 19, 21, 23, 20, 22, 24
603 : };
604 196 : foreach (const BBChord& c, bb.chords()) {
605 192 : Fraction tick = Fraction(c.beat, 4); // c.beat * Constants::division;
606 : // LOGD("CHORD %d %d", c.beat, tick);
607 192 : Measure* m = score->tick2measure(tick);
608 192 : if (m == 0) {
609 0 : LOGD("import BB: measure for tick %d not found", tick.ticks());
610 1 : continue;
611 : }
612 383 : if (c.root <= 0 || c.root > table.size()) {
613 1 : LOGE() << "Chord root out of range";
614 1 : continue;
615 : }
616 191 : Segment* s = m->getSegment(SegmentType::ChordRest, tick);
617 191 : Harmony* h = Factory::createHarmony(s);
618 191 : h->setTrack(0);
619 191 : HarmonyInfo* info = new HarmonyInfo(score);
620 191 : info->setRootTpc(table[c.root - 1]);
621 192 : if (c.bass > 0 && c.bass <= table.size()) {
622 0 : info->setBassTpc(table[c.bass - 1]);
623 : } else {
624 191 : info->setBassTpc(Tpc::TPC_INVALID);
625 : }
626 191 : info->setId(c.extension);
627 191 : h->addChord(info);
628 :
629 191 : s->add(h);
630 4 : }
631 :
632 : //---------------------------------------------------
633 : // insert layout breaks
634 : // add chorus repeat
635 : //---------------------------------------------------
636 :
637 4 : int startChorus = bb.startChorus() - 1;
638 4 : int endChorus = bb.endChorus() - 1;
639 :
640 4 : int n = 0;
641 200 : for (MeasureBase* mb = score->first(); mb; mb = mb->next()) {
642 196 : if (!mb->isMeasure()) {
643 4 : continue;
644 : }
645 192 : Measure* measure = (Measure*)mb;
646 192 : if (n && (n % 4) == 0) {
647 44 : LayoutBreak* lb = Factory::createLayoutBreak(measure);
648 44 : lb->setLayoutBreakType(LayoutBreakType::LINE);
649 44 : measure->add(lb);
650 : }
651 192 : if (startChorus == n) {
652 0 : measure->setRepeatStart(true);
653 192 : } else if (endChorus == n) {
654 0 : measure->setRepeatEnd(true);
655 0 : measure->setRepeatCount(bb.repeats());
656 : }
657 192 : ++n;
658 : }
659 :
660 8 : for (Staff* staff : score->staves()) {
661 4 : Fraction tick = Fraction(0, 1);
662 4 : KeySigEvent ke;
663 4 : Key key = Key(bb.key());
664 4 : Key cKey = key;
665 4 : Interval v = staff->part()->instrument(tick)->transpose();
666 4 : if (!v.isZero() && !score->style().styleB(Sid::concertPitch)) {
667 0 : cKey = Transpose::transposeKey(key, v);
668 : // if there are more than 6 accidentals in transposing key, it cannot be PreferSharpFlat::AUTO
669 0 : if ((key > 6 || key < -6) && staff->part()->preferSharpFlat() == PreferSharpFlat::AUTO) {
670 0 : staff->part()->setPreferSharpFlat(PreferSharpFlat::NONE);
671 : }
672 : }
673 4 : ke.setConcertKey(cKey);
674 4 : ke.setKey(key);
675 4 : staff->setKey(tick, ke);
676 4 : Measure* mks = score->tick2measure(tick);
677 4 : Segment* sks = mks->getSegment(SegmentType::KeySig, tick);
678 4 : KeySig* keysig = Factory::createKeySig(sks);
679 4 : keysig->setTrack((static_cast<int>(score->staffIdx(staff->part())) + staff->rstaff()) * VOICES);
680 4 : keysig->setKey(cKey, key);
681 4 : sks->add(keysig);
682 4 : }
683 4 : score->updateTicksAndTimeSigMap();
684 4 : return engraving::Err::NoError;
685 6 : }
686 :
687 : //---------------------------------------------------------
688 : // processPendingNotes
689 : //---------------------------------------------------------
690 :
691 0 : Fraction BBFile::processPendingNotes(Score* score, QList<MNote*>* notes, const Fraction& l, int track)
692 : {
693 0 : Fraction len(l);
694 0 : Staff* cstaff = score->staff(track / VOICES);
695 0 : const Instrument* instrument = cstaff->part()->instrument();
696 0 : const Drumset* drumset = instrument->drumset();
697 0 : bool useDrumset = instrument->useDrumset();
698 0 : Fraction tick = Fraction::fromTicks(notes->at(0)->mc.ontime());
699 :
700 : //
701 : // look for len of shortest note
702 : //
703 0 : for (const MNote* n : *notes) {
704 0 : if (n->mc.duration() < len.ticks()) {
705 0 : len = Fraction::fromTicks(n->mc.duration());
706 : }
707 : }
708 :
709 : //
710 : // split notes on measure boundary
711 : //
712 0 : Measure* measure = score->tick2measure(tick);
713 0 : if (measure == 0 || (tick >= measure->endTick())) {
714 0 : LOGD("no measure found for tick %d", tick.ticks());
715 0 : notes->clear();
716 0 : return len;
717 : }
718 0 : if ((tick + len) > measure->endTick()) {
719 0 : len = measure->endTick() - tick;
720 : }
721 :
722 0 : Segment* s = measure->getSegment(SegmentType::ChordRest, tick);
723 0 : Chord* chord = Factory::createChord(s);
724 0 : chord->setTrack(track);
725 0 : TDuration d;
726 0 : d.setVal(len.ticks());
727 0 : chord->setDurationType(d);
728 0 : chord->setTicks(d.fraction());
729 0 : s->add(chord);
730 :
731 0 : for (MNote* n : *notes) {
732 0 : std::vector<Event>& nl = n->mc.notes();
733 0 : for (size_t i = 0; i < nl.size(); ++i) {
734 0 : const Event& mn = nl[i];
735 0 : Note* note = Factory::createNote(chord);
736 0 : note->setPitch(mn.pitch(), mn.tpc(), mn.tpc());
737 0 : note->setTrack(track);
738 0 : chord->add(note);
739 :
740 0 : if (useDrumset) {
741 0 : if (!drumset->isValid(mn.pitch())) {
742 0 : LOGD("unmapped drum note 0x%02x %d", mn.pitch(), mn.pitch());
743 : } else {
744 0 : chord->setStemDirection(drumset->stemDirection(mn.pitch()));
745 : }
746 : }
747 0 : if (n->ties[static_cast<int>(i)]) {
748 0 : n->ties[static_cast<int>(i)]->setEndNote(note);
749 0 : n->ties[static_cast<int>(i)]->setTrack(note->track());
750 0 : note->setTieBack(n->ties[static_cast<int>(i)]);
751 : }
752 : }
753 0 : if (n->mc.duration() <= len.ticks()) {
754 0 : notes->removeAt(notes->indexOf(n));
755 0 : continue;
756 : }
757 0 : for (size_t i = 0; i < nl.size(); ++i) {
758 0 : const Event& mn = nl[i];
759 0 : Note* note = chord->findNote(mn.pitch());
760 0 : n->ties[static_cast<int>(i)] = Factory::createTie(note);
761 0 : n->ties[static_cast<int>(i)]->setStartNote(note);
762 0 : note->setTieFor(n->ties[static_cast<int>(i)]);
763 : }
764 0 : n->mc.setOntime(n->mc.ontime() + len.ticks());
765 0 : n->mc.setLen(n->mc.duration() - len.ticks());
766 : }
767 0 : return len;
768 : }
769 :
770 : //---------------------------------------------------------
771 : // collectNotes
772 : //---------------------------------------------------------
773 :
774 0 : static ciEvent collectNotes(const Fraction& tick, int voice, ciEvent i, const EventList* el, QList<MNote*>* notes)
775 : {
776 0 : for (; i != el->end(); ++i) {
777 0 : const Event& e = *i;
778 0 : if (e.type() != ME_CHORD) {
779 0 : continue;
780 : }
781 0 : if (e.voice() != voice) {
782 0 : continue;
783 : }
784 0 : if (e.ontime() > tick.ticks()) {
785 0 : break;
786 : }
787 0 : if (e.ontime() < tick.ticks()) {
788 0 : continue;
789 : }
790 0 : MNote* n = new MNote(e);
791 0 : notes->append(n);
792 : }
793 0 : return i;
794 : }
795 :
796 : //---------------------------------------------------------
797 : // convertTrack
798 : //---------------------------------------------------------
799 :
800 0 : void BBFile::convertTrack(Score* score, BBTrack* track, int staffIdx)
801 : {
802 0 : track->findChords();
803 0 : int voices = track->separateVoices(2);
804 0 : const EventList el = track->events();
805 :
806 0 : for (int voice = 0; voice < voices; ++voice) {
807 0 : int tr = staffIdx * VOICES + voice;
808 0 : QList<MNote*> notes;
809 :
810 0 : Fraction ctick = Fraction(0, 1);
811 0 : ciEvent i = collectNotes(ctick, voice, el.begin(), &el, ¬es);
812 :
813 0 : for (; i != el.end();) {
814 0 : const Event& e = *i;
815 0 : if (e.type() != ME_CHORD || e.voice() != voice) {
816 0 : ++i;
817 0 : continue;
818 : }
819 : //
820 : // process pending notes
821 : //
822 0 : Fraction restLen = Fraction::fromTicks(e.ontime()) - ctick;
823 : // LOGD("ctick %d rest %d ontick %d size %d", ctick, restLen, e.ontime(), notes.size());
824 :
825 0 : if (restLen <= Fraction(0, 1)) {
826 0 : ASSERT_X(QString::asprintf("bad restlen ontime %d - ctick %d", e.ontime(), ctick.ticks()));
827 : }
828 :
829 0 : while (!notes.isEmpty()) {
830 0 : Fraction len = processPendingNotes(score, ¬es, restLen, tr);
831 0 : if (len.isZero()) {
832 0 : LOGD("processPendingNotes returns zero, restlen %d, track %d", restLen.ticks(), tr);
833 0 : ctick += restLen;
834 0 : restLen = Fraction(0, 1);
835 0 : break;
836 : }
837 0 : ctick += len;
838 0 : restLen -= len;
839 : }
840 : // LOGD(" 1.ctick %d rest %d", ctick, restLen);
841 : //
842 : // check for gap and fill with rest
843 : //
844 0 : if (voice == 0) {
845 0 : while (restLen > Fraction(0, 1)) {
846 0 : Fraction len = restLen;
847 0 : Measure* measure = score->tick2measure(ctick);
848 0 : if (measure == 0 || (ctick >= measure->endTick())) { // at end?
849 0 : ctick += len;
850 0 : restLen -= len;
851 0 : break;
852 : }
853 : // split rest on measure boundary
854 0 : if ((ctick + len) > measure->endTick()) {
855 0 : len = measure->endTick() - ctick;
856 0 : if (len <= Fraction(0, 1)) {
857 0 : LOGD("bad len %d", len.ticks());
858 0 : break;
859 : }
860 : }
861 0 : TDuration d;
862 0 : d.setVal(len.ticks());
863 0 : Segment* s = measure->getSegment(SegmentType::ChordRest, ctick);
864 0 : Rest* rest = Factory::createRest(s, d);
865 0 : rest->setTicks(d.fraction());
866 0 : rest->setTrack(staffIdx * VOICES);
867 0 : s->add(rest);
868 : // LOGD(" add rest %d", len);
869 :
870 0 : ctick += len;
871 0 : restLen -= len;
872 : }
873 : } else {
874 0 : ctick += restLen;
875 : }
876 :
877 : // LOGD(" 2.ctick %d rest %d", ctick, restLen);
878 : //
879 : // collect all notes at ctick
880 : //
881 0 : i = collectNotes(ctick, voice, i, &el, ¬es);
882 : }
883 :
884 : //
885 : // process pending notes
886 : //
887 0 : while (!notes.isEmpty()) {
888 0 : Fraction len = processPendingNotes(score, ¬es, Fraction(0x7fffffff, 1), tr);
889 0 : ctick += len;
890 : }
891 0 : if (voice == 0) {
892 0 : Measure* measure = score->tick2measure(ctick);
893 0 : if (measure && (ctick < measure->endTick())) { // at end?
894 0 : TDuration d;
895 0 : d.setVal((measure->endTick() - ctick).ticks());
896 0 : Segment* s = measure->getSegment(SegmentType::ChordRest, ctick);
897 0 : Rest* rest = Factory::createRest(s, d);
898 0 : rest->setTicks(d.fraction());
899 0 : rest->setTrack(staffIdx * VOICES);
900 0 : s->add(rest);
901 : }
902 : }
903 0 : }
904 0 : }
905 :
906 : //---------------------------------------------------------
907 : // quantizeLen
908 : //---------------------------------------------------------
909 :
910 0 : int quantizeLen(int len, int raster)
911 : {
912 0 : if (raster == 0) {
913 0 : return len;
914 : }
915 0 : return int(((float)len / raster) + 0.5) * raster; //round to the closest multiple of raster
916 : }
917 :
918 : //---------------------------------------------------------
919 : // quantize
920 : // process one segment (measure)
921 : //---------------------------------------------------------
922 :
923 0 : void BBTrack::quantize(int startTick, int endTick, EventList* dst)
924 : {
925 0 : int mintick = Constants::DIVISION * 64;
926 0 : iEvent i = _events.begin();
927 0 : for (; i != _events.end(); ++i) {
928 0 : if (i->ontime() >= startTick) {
929 0 : break;
930 : }
931 : }
932 0 : iEvent si = i;
933 0 : for (; i != _events.end(); ++i) {
934 0 : const Event& e = *i;
935 0 : if (e.ontime() >= endTick) {
936 0 : break;
937 : }
938 0 : if (e.type() == ME_NOTE && (e.duration() < mintick)) {
939 0 : mintick = e.duration();
940 : }
941 : }
942 0 : if (mintick <= Constants::DIVISION / 16) { // minimum duration is 1/64
943 0 : mintick = Constants::DIVISION / 16;
944 0 : } else if (mintick <= Constants::DIVISION / 8) {
945 0 : mintick = Constants::DIVISION / 8;
946 0 : } else if (mintick <= Constants::DIVISION / 4) {
947 0 : mintick = Constants::DIVISION / 4;
948 0 : } else if (mintick <= Constants::DIVISION / 2) {
949 0 : mintick = Constants::DIVISION / 2;
950 0 : } else if (mintick <= Constants::DIVISION) {
951 0 : mintick = Constants::DIVISION;
952 0 : } else if (mintick <= Constants::DIVISION* 2) {
953 0 : mintick = Constants::DIVISION * 2;
954 0 : } else if (mintick <= Constants::DIVISION* 4) {
955 0 : mintick = Constants::DIVISION * 4;
956 0 : } else if (mintick <= Constants::DIVISION* 8) {
957 0 : mintick = Constants::DIVISION * 8;
958 : }
959 : int raster;
960 0 : if (mintick > Constants::DIVISION) {
961 0 : raster = Constants::DIVISION;
962 : } else {
963 0 : raster = mintick;
964 : }
965 :
966 : //
967 : // quantize onset
968 : //
969 0 : for (i = si; i != _events.end(); ++i) {
970 0 : Event e = *i;
971 0 : if (e.ontime() >= endTick) {
972 0 : break;
973 : }
974 0 : if (e.type() == ME_NOTE) {
975 : // prefer moving note to the right
976 0 : int tick = ((e.ontime() + raster / 2) / raster) * raster;
977 0 : int diff = tick - e.ontime();
978 0 : int len = e.duration() - diff;
979 0 : e.setOntime(tick);
980 0 : e.setLen(len);
981 : }
982 0 : dst->insert(e);
983 0 : }
984 : //
985 : // quantize duration
986 : //
987 0 : for (i = dst->begin(); i != dst->end(); ++i) {
988 0 : Event& e = *i;
989 0 : if (e.type() != ME_NOTE) {
990 0 : continue;
991 : }
992 0 : int tick = e.ontime();
993 0 : int len = e.duration();
994 0 : int ntick = tick + len;
995 0 : int nntick = -1;
996 0 : for (iEvent ii = (i + 1); ii != dst->end(); ++ii) {
997 0 : if (ii->type() == ME_NOTE) {
998 0 : const Event& ee = *ii;
999 0 : if (ee.ontime() == tick) {
1000 0 : continue;
1001 : }
1002 0 : nntick = ee.ontime();
1003 0 : break;
1004 : }
1005 : }
1006 0 : if (nntick == -1) {
1007 0 : len = quantizeLen(len, raster);
1008 : } else {
1009 0 : int diff = nntick - ntick;
1010 0 : if (diff > 0) {
1011 : // insert rest?
1012 0 : if (diff <= raster) {
1013 0 : len = nntick - tick;
1014 : } else {
1015 0 : len = quantizeLen(len, raster);
1016 : }
1017 : } else {
1018 0 : if (diff > -raster) {
1019 0 : len = nntick - tick;
1020 : } else {
1021 0 : len = quantizeLen(len, raster);
1022 : }
1023 : }
1024 : }
1025 0 : e.setLen(len);
1026 : }
1027 0 : }
1028 :
1029 : //---------------------------------------------------------
1030 : // cleanup
1031 : // - quantize
1032 : // - remove overlaps
1033 : //---------------------------------------------------------
1034 :
1035 0 : void BBTrack::cleanup()
1036 : {
1037 0 : EventList dl;
1038 :
1039 : //
1040 : // quantize
1041 : //
1042 0 : int lastTick = 0;
1043 0 : for (const Event& e : _events) {
1044 0 : if (e.type() != ME_NOTE) {
1045 0 : continue;
1046 : }
1047 0 : int offtime = e.offtime();
1048 0 : if (offtime > lastTick) {
1049 0 : lastTick = offtime;
1050 : }
1051 : }
1052 0 : int startTick = 0;
1053 0 : for (int i = 1;; ++i) {
1054 0 : int endTick = bb->siglist().bar2tick(i, 0);
1055 0 : quantize(startTick, endTick, &dl);
1056 0 : if (endTick > lastTick) {
1057 0 : break;
1058 : }
1059 0 : startTick = endTick;
1060 0 : }
1061 :
1062 : //
1063 : //
1064 : //
1065 0 : _events.clear();
1066 :
1067 0 : for (iEvent i = dl.begin(); i != dl.end(); ++i) {
1068 0 : Event& e = *i;
1069 0 : if (e.type() == ME_NOTE) {
1070 0 : iEvent ii = i;
1071 0 : ++ii;
1072 0 : for (; ii != dl.end(); ++ii) {
1073 0 : const Event& ee = *ii;
1074 0 : if (ee.type() != ME_NOTE || ee.pitch() != e.pitch()) {
1075 0 : continue;
1076 : }
1077 0 : if (ee.ontime() >= e.ontime() + e.duration()) {
1078 0 : break;
1079 : }
1080 0 : e.setLen(ee.ontime() - e.ontime());
1081 0 : break;
1082 : }
1083 0 : if (e.duration() <= 0) {
1084 0 : continue;
1085 : }
1086 : }
1087 0 : _events.insert(e);
1088 : }
1089 0 : }
1090 :
1091 : //---------------------------------------------------------
1092 : // findChords
1093 : //---------------------------------------------------------
1094 :
1095 0 : void BBTrack::findChords()
1096 : {
1097 0 : EventList dl;
1098 0 : size_t n = _events.size();
1099 :
1100 : Drumset* drumset;
1101 0 : if (_drumTrack) {
1102 0 : drumset = smDrumset;
1103 : } else {
1104 0 : drumset = 0;
1105 : }
1106 0 : int jitter = 3; // tick tolerance for note on/off
1107 :
1108 0 : for (size_t i = 0; i < n; ++i) {
1109 0 : Event e = _events[i];
1110 0 : if (e.type() == ME_INVALID) {
1111 0 : continue;
1112 : }
1113 0 : if (e.type() != ME_NOTE) {
1114 0 : dl.push_back(e);
1115 0 : continue;
1116 : }
1117 :
1118 0 : Event note(e);
1119 0 : int ontime = note.ontime();
1120 0 : int offtime = note.offtime();
1121 0 : Event chord(ME_CHORD);
1122 0 : chord.setOntime(ontime);
1123 0 : chord.setLen(note.duration());
1124 0 : chord.notes().push_back(note);
1125 0 : int voice = 0;
1126 0 : chord.setVoice(voice);
1127 0 : dl.push_back(chord);
1128 0 : _events[i].setType(ME_INVALID);
1129 :
1130 0 : bool useDrumset = false;
1131 0 : if (drumset) {
1132 0 : int pitch = note.pitch();
1133 0 : if (drumset->isValid(pitch)) {
1134 0 : useDrumset = true;
1135 0 : voice = drumset->voice(pitch);
1136 0 : chord.setVoice(voice);
1137 : }
1138 : }
1139 0 : for (size_t k = i + 1; k < n; ++k) {
1140 0 : if (_events[k].type() != ME_NOTE) {
1141 0 : continue;
1142 : }
1143 0 : Event nn = _events[k];
1144 0 : if (nn.ontime() - jitter > ontime) {
1145 0 : break;
1146 : }
1147 0 : if (qAbs(nn.ontime() - ontime) > jitter || qAbs(nn.offtime() - offtime) > jitter) {
1148 0 : continue;
1149 : }
1150 0 : int pitch = nn.pitch();
1151 0 : if (useDrumset) {
1152 0 : if (drumset->isValid(pitch) && drumset->voice(pitch) == voice) {
1153 0 : chord.notes().push_back(nn);
1154 0 : _events[k].setType(ME_INVALID);
1155 : }
1156 : } else {
1157 0 : chord.notes().push_back(nn);
1158 0 : _events[k].setType(ME_INVALID);
1159 : }
1160 0 : }
1161 0 : }
1162 0 : _events = dl;
1163 0 : }
1164 :
1165 : //---------------------------------------------------------
1166 : // separateVoices
1167 : //---------------------------------------------------------
1168 :
1169 0 : int BBTrack::separateVoices(int /*maxVoices*/)
1170 : {
1171 0 : return 1;
1172 : }
1173 : }
|