1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2010-2011 Werner Schweer
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2
9 // as published by the Free Software Foundation and appearing in
10 // the file LICENCE.GPL
11 //=============================================================================
12
13 #include "score.h"
14 #include "slur.h"
15 #include "measure.h"
16 #include "tuplet.h"
17 #include "chordrest.h"
18 #include "rest.h"
19 #include "segment.h"
20 #include "staff.h"
21 #include "keysig.h"
22 #include "clef.h"
23 #include "utils.h"
24
25 namespace Ms {
26
27 //---------------------------------------------------------
28 // checkSlurs
29 // helper routine to check for sanity slurs
30 //---------------------------------------------------------
31
checkSlurs()32 void Score::checkSlurs()
33 {
34 #if 0 //TODO1
35 foreach(Element* e, _gel) {
36 if (e->type() != SLUR)
37 continue;
38 Slur* s = (Slur*)e;
39 Element* n1 = s->startElement();
40 Element* n2 = s->endElement();
41 if (n1 == 0 || n2 == 0 || n1 == n2) {
42 qDebug("unconnected slur: removing");
43 if (n1) {
44 ((ChordRest*)n1)->removeSlurFor(s);
45 ((ChordRest*)n1)->removeSlurBack(s);
46 }
47 if (n1 == 0)
48 qDebug(" start at %d(%d) not found", s->tick(), s->track());
49 if (n2 == 0)
50 qDebug(" end at %d(%d) not found", s->tick2(), s->track2());
51 if ((n1 || n2) && (n1==n2))
52 qDebug(" start == end");
53 int idx = _gel.indexOf(s);
54 _gel.removeAt(idx);
55 }
56 }
57 #endif
58 }
59
60 //---------------------------------------------------------
61 // checkScore
62 //---------------------------------------------------------
63
checkScore()64 void Score::checkScore()
65 {
66 if (!firstMeasure())
67 return;
68 #if 0
69 for (Measure* m = firstMeasure(); m; m = m->nextMeasure())
70 m->segments()->check();
71 #endif
72 for (Segment* s = firstMeasure()->first(); s;) {
73 Segment* ns = s->next1();
74
75 if (s->segmentType() & (SegmentType::ChordRest)) {
76 bool empty = true;
77 foreach(Element* e, s->elist()) {
78 if (e) {
79 empty = false;
80 break;
81 }
82 }
83 if (empty) {
84 // Measure* m = s->measure();
85 qDebug("checkScore: remove empty ChordRest segment");
86 // m->remove(s);
87 }
88 }
89 s = ns;
90 }
91
92 checkSlurs();
93
94 ChordRest* lcr = 0;
95 for (int staffIdx = 0; staffIdx < _staves.size(); ++staffIdx) {
96 int track = staffIdx * VOICES;
97 Fraction tick = Fraction(0,1);
98 Staff* st = staff(staffIdx);
99 for (Segment* s = firstMeasure()->first(SegmentType::ChordRest); s; s = s->next1(SegmentType::ChordRest)) {
100 ChordRest* cr = toChordRest(s->element(track));
101 if (!cr)
102 continue;
103 if (s->tick() != tick) {
104 if (lcr) {
105 Fraction timeStretch = st->timeStretch(lcr->tick());
106 Fraction f = cr->globalTicks() * timeStretch;
107 qDebug("Chord/Rest gap at tick %d(%s+%d)-%d(%s) staffIdx %d measure %d (len = %d)",
108 tick.ticks(), lcr->name(), f.ticks(),
109 s->tick().ticks(), cr->name(), staffIdx, cr->measure()->no(),
110 (cr->tick() - tick).ticks());
111 }
112 else {
113 qDebug("Chord/Rest gap at tick %d-%d(%s) staffIdx %d measure %d (len = %d)",
114 tick.ticks(),
115 s->tick().ticks(), cr->name(), staffIdx, cr->measure()->no(),
116 (cr->tick() - tick).ticks());
117 }
118 #if 0
119 if (cr->tick() > tick) {
120 int ttick = tick;
121 int ticks = cr->tick() - tick;
122
123 Fraction f = Fraction::fromTicks(ticks) / st->timeStretch(ttick);
124 qDebug(" insert %d/%d", f.numerator(), f.denominator());
125
126 while (ticks > 0) {
127 Measure* m = tick2measure(ttick);
128 int len = ticks;
129 // split notes on measure boundary
130 if ((ttick + len) > m->tick() + m->ticks())
131 len = m->tick() + m->ticks() - ttick;
132 Fraction timeStretch = st->timeStretch(ttick);
133 Fraction ff = Fraction::fromTicks(len);
134 qDebug(" - insert %d/%d", ff.numerator(), ff.denominator());
135 if (ff.numerator() == 0)
136 break;
137 Fraction fff = ff / timeStretch;
138
139 for (const Duration& d, toDurationList(fff, true)) {
140 Rest* rest = new Rest(this);
141 rest->setDurationType(d);
142 rest->setDuration(d.fraction());
143 rest->setColor(Qt::red);
144 qDebug(" - Rest %d/%d", d.fraction().numerator(), d.fraction().denominator());
145 rest->setTrack(track);
146 Segment* s = m->getSegment(rest, ttick);
147 s->add(rest);
148 ttick += (d.fraction() * timeStretch).ticks();
149 }
150 ticks -= len;
151 }
152 }
153 #endif
154 tick = s->tick();
155 }
156 Fraction timeStretch = st->timeStretch(tick);
157 Fraction f = cr->globalTicks() * timeStretch;
158 // qDebug("%s %d + %d = %d", cr->name(), tick, f.ticks(), tick + f.ticks());
159 tick += f;
160 lcr = cr;
161 }
162 }
163 }
164
165 //---------------------------------------------------------
166 // sanityCheck - Simple check for score
167 /// Check that voice 1 is complete
168 /// Check that voices > 1 contains less than measure duration
169 //---------------------------------------------------------
170
sanityCheck(const QString & name)171 bool Score::sanityCheck(const QString& name)
172 {
173 bool result = true;
174 int mNumber = 1;
175 QString error;
176 for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
177 Fraction mLen = m->ticks();
178 int endStaff = staves().size();
179 for (int staffIdx = 0; staffIdx < endStaff; ++staffIdx) {
180 Rest* fmrest0 = 0; // full measure rest in voice 0
181 Fraction voices[VOICES];
182 #ifndef NDEBUG
183 m->setCorrupted(staffIdx, false);
184 #endif
185 for (Segment* s = m->first(SegmentType::ChordRest); s; s = s->next(SegmentType::ChordRest)) {
186 for (int v = 0; v < VOICES; ++v) {
187 ChordRest* cr = toChordRest(s->element(staffIdx * VOICES + v));
188 if (cr == 0)
189 continue;
190 voices[v] += cr->actualTicks();
191 if (v == 0 && cr->isRest()) {
192 Rest* r = toRest(cr);
193 if (r->durationType().isMeasure()) {
194 fmrest0 = r;
195 }
196 }
197 }
198 }
199 if (voices[0] != mLen) {
200 QString msg = QObject::tr("Measure %1, staff %2 incomplete. Expected: %3; Found: %4").arg(mNumber).arg(staffIdx + 1).arg(mLen.print(), voices[0].print());
201 qDebug() << msg;
202 error += QString("%1\n").arg(msg);
203 #ifndef NDEBUG
204 m->setCorrupted(staffIdx, true);
205 #endif
206 result = false;
207 // try to fix a bad full measure rest
208 if (fmrest0) {
209 // fmrest0->setDuration(mLen * fmrest0->staff()->timeStretch(fmrest0->tick()));
210 fmrest0->setTicks(mLen);
211 if (fmrest0->actualTicks() != mLen)
212 fprintf(stderr,"whoo???\n");
213 }
214 }
215 for (int v = 1; v < VOICES; ++v) {
216 if (voices[v] > mLen) {
217 QString msg = QObject::tr("Measure %1, staff %2, voice %3 too long. Expected: %4; Found: %5").arg(mNumber).arg(staffIdx + 1).arg(v + 1).arg(mLen.print(), voices[v].print());
218 qDebug() << msg;
219 error += QString("%1\n").arg(msg);
220 #ifndef NDEBUG
221 m->setCorrupted(staffIdx, true);
222 #endif
223 result = false;
224 }
225 }
226 }
227 mNumber++;
228 }
229 if (!name.isEmpty()) {
230 QJsonObject json;
231 if (result) {
232 json["result"] = 0;
233 }
234 else {
235 json["result"] = 1;
236 json["error"] = error.trimmed().replace("\n", "\\n");
237 }
238 QJsonDocument jsonDoc(json);
239 QFile fp(name);
240 if (!fp.open(QIODevice::WriteOnly)) {
241 qDebug("Open <%s> failed", qPrintable(name));
242 return false;
243 }
244 fp.write(jsonDoc.toJson(QJsonDocument::Compact));
245 fp.close();
246 }
247 else {
248 MScore::lastError = error;
249 }
250 return result;
251 }
252
253 //---------------------------------------------------------
254 // checkKeys
255 /// check that key map is in sync with actual keys
256 //---------------------------------------------------------
257
checkKeys()258 bool Score::checkKeys()
259 {
260 bool rc = true;
261 for (int i = 0; i < nstaves(); ++i) {
262 Key k = staff(i)->key(Fraction(0,1));
263 for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
264 Segment* s = m->findSegment(SegmentType::KeySig, m->tick());
265 if (s) {
266 Element* element = s->element(i * VOICES);
267 if (element)
268 k = toKeySig(element)->key();
269 }
270 if (staff(i)->key(m->tick()) != k) {
271 qDebug("measure %d (tick %d) : key %d, map %d", m->no(), m->tick().ticks(), int(k),
272 int(staff(i)->key(m->tick())));
273 rc = false;
274 }
275 }
276 }
277 return rc;
278 }
279
280 //---------------------------------------------------------
281 // checkClefs
282 /// check that clef map is in sync with actual clefs
283 //---------------------------------------------------------
284
checkClefs()285 bool Score::checkClefs()
286 {
287 bool rc = true;
288 //TODO:ws what about clefs not at measure start?
289
290 #if 0
291 int track = 0;
292 for (Staff* staff : _staves) {
293 ClefType clefType = staff->clef(0);
294 Measure* prevMeasure = 0;
295
296 for (Measure* m = firstMeasure(); m; m = m->nextMeasure()) {
297 if (prevMeasure) {
298 Segment* segment = prevMeasure->findSegmentR(SegmentType::Clef | SegmentType::HeaderClef, 0);
299 if (segment) {
300 Element* e = segment->element(track);
301 if (e)
302 clefType = toClef(e)->clefType();
303 }
304 }
305 ClefType mapClefType = staff->clef(m->tick());
306 if (mapClefType != clefType) {
307 qDebug("measure %d (tick %d) : clef %d, map %d", m->no(), m->tick(), int(clefType), int(mapClefType));
308 rc = false;
309 }
310 prevMeasure = m;
311 }
312 track += VOICES;
313 }
314 #endif
315 return rc;
316 }
317
318 //---------------------------------------------------------
319 // fillGap
320 //---------------------------------------------------------
321
fillGap(const Fraction & pos,const Fraction & len,int track,const Fraction & stretch)322 void Measure::fillGap(const Fraction& pos, const Fraction& len, int track, const Fraction& stretch)
323 {
324 qDebug("measure %6d pos %d, len %d/%d, stretch %d/%d track %d",
325 tick().ticks(),
326 pos.ticks(),
327 len.numerator(), len.denominator(),
328 stretch.numerator(), stretch.denominator(),
329 track);
330 TDuration d;
331 d.setVal(len.ticks());
332 if (d.isValid()) {
333 Rest* rest = new Rest(score());
334 rest->setTicks(len);
335 rest->setDurationType(d);
336 rest->setTrack(track);
337 rest->setGap(true);
338 score()->undoAddCR(rest, this, (pos / stretch) + tick());
339 }
340 }
341
342 //---------------------------------------------------------
343 // checkMeasure
344 // after opening / paste and every read operation
345 // this method checks for gaps and fills them
346 // with invisible rests
347 //---------------------------------------------------------
348
checkMeasure(int staffIdx)349 void Measure::checkMeasure(int staffIdx)
350 {
351 if (isMMRest())
352 return;
353
354 int strack = staffIdx * VOICES;
355 int dtrack = strack + (hasVoices(staffIdx) ? VOICES : 1);
356 Fraction stretch = score()->staff(staffIdx)->timeStretch(tick());
357 Fraction f = ticks() * stretch;
358
359 for (int track = strack; track < dtrack; track++) {
360 Fraction expectedPos = Fraction(0,1);
361 Fraction currentPos = Fraction(0,1);
362
363 for (Segment* seg = first(SegmentType::ChordRest); seg; seg = seg->next(SegmentType::ChordRest)) {
364 Element* e = seg->element(track);
365 if (!e)
366 continue;
367
368 ChordRest* cr = toChordRest(e);
369 currentPos = seg->rtick() * stretch;
370
371 if (currentPos < expectedPos) {
372 qDebug("in measure overrun %6d at %d-%d track %d", tick().ticks(), (currentPos/stretch).ticks(), (expectedPos/stretch).ticks(), track);
373 break;
374 }
375 else if (currentPos > expectedPos) {
376 qDebug("in measure underrun %6d at %d-%d track %d", tick().ticks(), (currentPos/stretch).ticks(), (expectedPos/stretch).ticks(), track);
377 fillGap(expectedPos, currentPos - expectedPos, track, stretch);
378 }
379
380 DurationElement* de = cr;
381 Tuplet* tuplet = cr->topTuplet();
382 if (tuplet) {
383 seg = skipTuplet(tuplet);
384 de = tuplet;
385 }
386 expectedPos = currentPos + de->ticks();
387 }
388 if (f > expectedPos) {
389 // don't fill empty voices
390 if (expectedPos.isNotZero())
391 fillGap(expectedPos, f - expectedPos, track, stretch);
392 }
393 else if (f < expectedPos)
394 qDebug("measure overrun %6d, %d > %d, track %d", tick().ticks(), expectedPos.ticks(), f.ticks(), track);
395 }
396 }
397
398 }
399
400