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