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() const35const 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() const46StaffGroup 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() const64Fraction InputState::tick() const 65 { 66 return _segment ? _segment->tick() : Fraction(0,1); 67 } 68 69 //--------------------------------------------------------- 70 // cr 71 //--------------------------------------------------------- 72 cr() const73ChordRest* 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)83void 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)94Note* InputState::note(Element* e) 95 { 96 return e && e->isNote() ? toNote(e) : nullptr; 97 } 98 99 //--------------------------------------------------------- 100 // chordRest 101 //--------------------------------------------------------- 102 chordRest(Element * e)103ChordRest* 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)122void 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)195void 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)220void 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() const234Segment* 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()256void InputState::moveToNextInputPos() 257 { 258 Segment* s = nextInputPos(); 259 _lastSegment = _segment; 260 if (s) 261 _segment = s; 262 } 263 264 //--------------------------------------------------------- 265 // endOfScore 266 //--------------------------------------------------------- 267 endOfScore() const268bool InputState::endOfScore() const 269 { 270 return (_lastSegment == _segment) && !nextInputPos(); 271 } 272 273 274 } 275 276