1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2011 Werner Schweer and others
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 LICENSE.GPL
11 //=============================================================================
12 
13 #include "input.h"
14 #include "segment.h"
15 #include "part.h"
16 #include "staff.h"
17 #include "stem.h"
18 #include "hook.h"
19 #include "score.h"
20 #include "chord.h"
21 #include "rest.h"
22 #include "measure.h"
23 #include "accidental.h"
24 #include "durationtype.h"
25 #include "select.h"
26 
27 namespace Ms {
28 
29 class DrumSet;
30 
31 //---------------------------------------------------------
32 //   drumset
33 //---------------------------------------------------------
34 
drumset() const35 const Drumset* InputState::drumset() const
36       {
37       if (_segment == 0 || _track == -1)
38             return 0;
39       return _segment->score()->staff(_track/VOICES)->part()->instrument(_segment->tick())->drumset();
40       }
41 
42 //---------------------------------------------------------
43 //   staffGroup
44 //---------------------------------------------------------
45 
staffGroup() const46 StaffGroup InputState::staffGroup() const
47       {
48       if (_segment == 0 || _track == -1)
49             return StaffGroup::STANDARD;
50 
51       StaffGroup staffGroup = _segment->score()->staff(_track/VOICES)->staffType(_segment->tick())->group();
52       Instrument* instrument = _segment->score()->staff(_track/VOICES)->part()->instrument(_segment->tick());
53 
54       // if not tab, pitched/unpitched input depends on instrument, not staff (override StaffGroup)
55       if ( staffGroup != StaffGroup::TAB)
56             staffGroup = instrument->useDrumset() ? StaffGroup::PERCUSSION : StaffGroup::STANDARD;
57       return staffGroup;
58       }
59 
60 //---------------------------------------------------------
61 //   tick
62 //---------------------------------------------------------
63 
tick() const64 Fraction InputState::tick() const
65       {
66       return _segment ? _segment->tick() : Fraction(0,1);
67       }
68 
69 //---------------------------------------------------------
70 //   cr
71 //---------------------------------------------------------
72 
cr() const73 ChordRest* InputState::cr() const
74       {
75       // _track could potentially be -1, for instance after navigation through a frame
76       return _segment && _track >= 0 ? toChordRest(_segment->element(_track)) : 0;
77       }
78 
79 //---------------------------------------------------------
80 //   setDots
81 //---------------------------------------------------------
82 
setDots(int n)83 void InputState::setDots(int n)
84       {
85       if (n && (!_duration.isValid() || _duration.isZero() || _duration.isMeasure()))
86             _duration = TDuration::DurationType::V_QUARTER;
87       _duration.setDots(n);
88       }
89 
90 //---------------------------------------------------------
91 //   note
92 //---------------------------------------------------------
93 
note(Element * e)94 Note* InputState::note(Element* e)
95       {
96       return e && e->isNote() ? toNote(e) : nullptr;
97       }
98 
99 //---------------------------------------------------------
100 //   chordRest
101 //---------------------------------------------------------
102 
chordRest(Element * e)103 ChordRest* InputState::chordRest(Element* e)
104       {
105       if (!e)
106             return nullptr;
107       if (e->isChordRest())
108             return toChordRest(e);
109       if (e->isNote())
110             return toNote(e)->chord();
111       if (e->isStem())
112             return toStem(e)->chord();
113       if (e->isHook())
114             return toHook(e)->chord();
115       return nullptr;
116       }
117 
118 //---------------------------------------------------------
119 //   update
120 //---------------------------------------------------------
121 
update(Selection & selection)122 void InputState::update(Selection& selection)
123       {
124       setDuration(TDuration::DurationType::V_INVALID);
125       setRest(false);
126       setAccidentalType(AccidentalType::NONE);
127       Note* n1 = nullptr;
128       ChordRest* cr1 = nullptr;
129       bool differentAccidentals = false;
130       bool differentDurations = false;
131       bool chordsAndRests = false;
132       for (Element* e : selection.elements()) {
133             if (Note* n = note(e)) {
134                   if (n1) {
135                         if (n->accidentalType() != n1->accidentalType()) {
136                               setAccidentalType(AccidentalType::NONE);
137                               differentAccidentals = true;
138                               }
139                         }
140                   else {
141                         setAccidentalType(n->accidentalType());
142                         n1 = n;
143                         }
144                   }
145 
146             if (ChordRest* cr = chordRest(e)) {
147                   if (cr1) {
148                         if (cr->durationType() != cr1->durationType()) {
149                               setDuration(TDuration::DurationType::V_INVALID);
150                               differentDurations = true;
151                               }
152                         if ((cr->isRest() && !cr1->isRest()) || (!cr->isRest() && cr1->isRest())) {
153                               setRest(false);
154                               chordsAndRests = true;
155                               }
156                         }
157                   else {
158                         setDuration(cr->durationType());
159                         setRest(cr->isRest());
160                         cr1 = cr;
161                         }
162                   }
163 
164             if (differentAccidentals && differentDurations && chordsAndRests)
165                   break;
166             }
167 
168       Element* e = selection.element();
169       if (e == 0)
170             return;
171 
172       ChordRest* cr = chordRest(e);
173       Note* n = note(e);
174       if (!n && cr && cr->isChord())
175             n = toChord(cr)->upNote();
176 
177       if (cr) {
178             setTrack(cr->track());
179             setNoteType(n ? n->noteType() : NoteType::NORMAL);
180             setBeamMode(cr->beamMode());
181             }
182 
183       setDrumNote(-1);
184       if (n) {
185             const Instrument* instr = n->part()->instrument(n->tick());
186             if (instr->useDrumset())
187                   setDrumNote(n->pitch());
188             }
189       }
190 
191 //---------------------------------------------------------
192 //   moveInputPos
193 //---------------------------------------------------------
194 
moveInputPos(Element * e)195 void InputState::moveInputPos(Element* e)
196       {
197       if (e == 0)
198             return;
199 
200       Segment* s;
201       if (e->isChordRest())
202             s = toChordRest(e)->segment();
203       else
204             s = toSegment(e);
205 
206       if (s->isSegment()) {
207             if (s->measure()->isMMRest()) {
208                   Measure* m = s->measure()->mmRestFirst();
209                   s = m->findSegment(SegmentType::ChordRest, m->tick());
210                   }
211             _lastSegment = _segment;
212             _segment = s;
213             }
214       }
215 
216 //---------------------------------------------------------
217 //   setSegment
218 //---------------------------------------------------------
219 
setSegment(Segment * s)220 void InputState::setSegment(Segment* s)
221       {
222       if (s && s->measure()->isMMRest()) {
223             Measure* m = s->measure()->mmRestFirst();
224             s = m->findSegment(SegmentType::ChordRest, m->tick());
225             }
226       _segment = s;
227       _lastSegment = s;
228       }
229 
230 //---------------------------------------------------------
231 //   nextInputPos
232 //---------------------------------------------------------
233 
nextInputPos() const234 Segment* InputState::nextInputPos() const
235       {
236       Measure* m = _segment->measure();
237       Segment* s = _segment->next1(SegmentType::ChordRest);
238       for (; s; s = s->next1(SegmentType::ChordRest)) {
239             if (s->element(_track)) {
240                   if (s->element(_track)->isRest() && toRest(s->element(_track))->isGap())
241                         m = s->measure();
242                   else
243                         return s;
244                   }
245             else if (s->measure() != m)
246                   return s;
247             }
248       return 0;
249       }
250 
251 //---------------------------------------------------------
252 //   moveToNextInputPos
253 //   TODO: special case: note is first note of tie: goto to last note of tie
254 //---------------------------------------------------------
255 
moveToNextInputPos()256 void InputState::moveToNextInputPos()
257       {
258       Segment* s   = nextInputPos();
259       _lastSegment = _segment;
260       if (s)
261             _segment = s;
262       }
263 
264 //---------------------------------------------------------
265 //   endOfScore
266 //---------------------------------------------------------
267 
endOfScore() const268 bool InputState::endOfScore() const
269       {
270       return (_lastSegment == _segment) && !nextInputPos();
271       }
272 
273 
274 }
275 
276