1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2013 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 "importmidi_tie.h"
14 #include "libmscore/element.h"
15 #include "libmscore/segment.h"
16 #include "libmscore/chordrest.h"
17 #include "libmscore/chord.h"
18 #include "libmscore/note.h"
19 
20 #ifdef QT_DEBUG
21 #include "libmscore/staff.h"
22 #include "libmscore/score.h"
23 #include "libmscore/measure.h"
24 #endif
25 
26 
27 namespace Ms {
28 namespace MidiTie {
29 
30 
isTied(const Segment * seg,int strack,int voice,Ms::Tie * (Note::* tieFunc)()const)31 bool isTied(const Segment *seg, int strack, int voice,
32             Ms::Tie*(Note::*tieFunc)() const)
33       {
34       ChordRest *cr = static_cast<ChordRest *>(seg->element(strack + voice));
35       if (cr && cr->isChord()) {
36             Chord *chord = toChord(cr);
37             const auto &notes = chord->notes();
38             for (const Note *note: notes) {
39                   if ((note->*tieFunc)())
40                         return true;
41                   }
42             }
43       return false;
44       }
45 
isTiedFor(const Segment * seg,int strack,int voice)46 bool isTiedFor(const Segment *seg, int strack, int voice)
47       {
48       return isTied(seg, strack, voice, &Note::tieFor);
49       }
50 
isTiedBack(const Segment * seg,int strack,int voice)51 bool isTiedBack(const Segment *seg, int strack, int voice)
52       {
53       return isTied(seg, strack, voice, &Note::tieBack);
54       }
55 
56 
addSeg(const Segment * seg,int strack)57 void TieStateMachine::addSeg(const Segment *seg, int strack)
58       {
59       bool isChord = false;
60       for (int voice = 0; voice < VOICES; ++voice) {
61             ChordRest *cr = static_cast<ChordRest *>(seg->element(strack + voice));
62             if (!cr || !cr->isChord())
63                   continue;
64             if (!isChord)
65                   isChord = true;
66 
67             bool tiedFor = isTiedFor(seg, strack, voice);
68             bool tiedBack = isTiedBack(seg, strack, voice);
69 
70             if (tiedFor && !tiedBack)
71                   tiedVoices.insert(voice);
72             else if (!tiedFor && tiedBack)
73                   tiedVoices.erase(voice);
74             }
75       if (!isChord)
76             return;
77 
78       if (tiedVoices.empty() && (state_ == State::TIED_FOR
79                                  || state_ == State::TIED_BOTH)) {
80             state_ = State::TIED_BACK;
81             }
82       else if (tiedVoices.empty() && state_ == State::TIED_BACK) {
83             state_ = State::UNTIED;
84             }
85       else if (!tiedVoices.empty() && (state_ == State::TIED_BACK
86                                        || state_ == State::UNTIED)) {
87             state_ = State::TIED_FOR;
88             }
89       else if (!tiedVoices.empty() && state_ == State::TIED_FOR) {
90             state_ = State::TIED_BOTH;
91             }
92       }
93 
94 
95 #ifdef QT_DEBUG
96 
printInconsistentTieLocation(int measureIndex,int staffIndex)97 void printInconsistentTieLocation(int measureIndex, int staffIndex)
98       {
99       qDebug() << "Ties are inconsistent; measure number (from 1):"
100                << measureIndex + 1
101                << ", staff index (from 0):" << staffIndex;
102       }
103 
areTiesConsistent(const Staff * staff)104 bool areTiesConsistent(const Staff *staff)
105       {
106       const int strack = staff->idx() * VOICES;
107 
108       for (int voice = 0; voice < VOICES; ++voice) {
109             bool isTie = false;
110             for (Segment *seg = staff->score()->firstSegment(SegmentType::All); seg; seg = seg->next1()) {
111                   if (seg->segmentType() == SegmentType::ChordRest) {
112                         ChordRest *cr = static_cast<ChordRest *>(seg->element(strack + voice));
113 
114                         if (cr && cr->isRest() && isTie) {
115                               printInconsistentTieLocation(seg->measure()->no(), staff->idx());
116                               return false;
117                               }
118                         if (isTiedBack(seg, strack, voice)) {
119                               if (!isTie) {
120                                     printInconsistentTieLocation(seg->measure()->no(), staff->idx());
121                                     return false;
122                                     }
123                               isTie = false;
124                               }
125                         if (isTiedFor(seg, strack, voice)) {
126                               if (isTie) {
127                                     printInconsistentTieLocation(seg->measure()->no(), staff->idx());
128                                     return false;
129                                     }
130                               isTie = true;
131                               }
132                         }
133                   }
134             if (isTie)
135                   return false;
136             }
137       return true;
138       }
139 
140 #endif
141 
142 
143 } // namespace MidiTie
144 } // namespace Ms
145 
146