Author: Maurizio Gavioli <mmg@vistamaresoft.com>  2012-08-03 01:28:02
Committer: Maurizio Gavioli <mmg@vistamaresoft.com>  2012-08-03 01:28:02
Parent: 5d88e6b63e489c20aa1b10d8c628ecc00c357585 (Merge branch 'master' of github.com:musescore/MuseScore)
Branches: new_note_input_method, remotes/origin/new_note_input_method
Follows: 
Precedes: 

    Modified scoreview.cpp/.h to take into account previous accidentals in measure in addition to key sig. accidentals.

----------------------------- mscore/scoreview.cpp -----------------------------
index d19ea39..178f83e 100644
@@ -81,6 +81,18 @@
 #include "navigator.h"
 #include "inspector.h"
 
+// a useful enum for scale steps (could be moved to libmscore/pitchspelling.h)
+enum {
+      STEP_NONE      = -1,
+      STEP_C,
+      STEP_D,
+      STEP_E,
+      STEP_F,
+      STEP_G,
+      STEP_A,
+      STEP_B
+};
+
 static const QEvent::Type CloneDrag = QEvent::Type(QEvent::User + 1);
 extern TextPalette* textPalette;
 
@@ -4833,9 +4845,10 @@ void ScoreView::cmdAddPitch(int note, bool addFlag)
             is.setDrumNote(pitch);
             }
       else {
-            KeySigEvent key = _score->staff(is.track() / VOICES)->keymap()->key(is.tick());
+//            KeySigEvent key = _score->staff(is.track() / VOICES)->keymap()->key(is.tick());
             int octave = is.pitch / 12;
-            pitch      = pitchKeyAdjust(note, key.accidentalType());
+//            pitch      = pitchKeyAdjust(note, key.accidentalType());
+            pitch      = pitchKeyAdjust(note, 0);     // for now, no accidentals (cmdAddPitch1() will compute them)
             int delta  = is.pitch - (octave*12 + pitch);
             if (delta > 6)
                   is.pitch = (octave+1)*12 + pitch;
@@ -4849,7 +4862,7 @@ void ScoreView::cmdAddPitch(int note, bool addFlag)
                   is.pitch = 127;
             pitch = is.pitch;
             }
-      cmdAddPitch1(pitch, addFlag);
+      cmdAddPitch1(pitch, addFlag, note);
       }
 
 //---------------------------------------------------------
@@ -5060,7 +5073,7 @@ void ScoreView::cmdRepeatSelection()
       const Selection& selection = _score->selection();
       if (selection.isSingle() && noteEntryMode()) {
             const InputState& is = _score->inputState();
-            cmdAddPitch1(is.pitch, false);
+            cmdAddPitch1(is.pitch, false, STEP_NONE);
             return;
             }
 
@@ -5201,11 +5214,24 @@ static void wrongPosition()
 
 //---------------------------------------------------------
 //   cmdAddPitch1
+//
+//    Modified to compute note pitch and tpc according to measure context
+//    in addition to key signature, if step != STEP_NONE
+//    (emun for steps provisionaly added at the beginning of this file)
+//
+//    Note: if step != STEP_NONE, assumes pitch to be for note with no accidental
+//
+//    Deals with keyboard input (both for new chord and for adding new note to existing chord);
+//    Does NOT deal with mouse input.
+//
+//    Added parameter 'step' to hold scale step (C=0, D=1, ...) if actual pitch / tpc have to be computed
+//    or STEP_NONE if pitch has to be taken literaly (no context effect).
 //---------------------------------------------------------
 
-void ScoreView::cmdAddPitch1(int pitch, bool addFlag)
+void ScoreView::cmdAddPitch1(int pitch, bool addFlag, int step)
       {
       InputState& is = _score->inputState();
+      Drumset *   drumSet     = is.drumset();
 
       if (is.segment() == 0) {
             wrongPosition();
@@ -5223,21 +5249,96 @@ void ScoreView::cmdAddPitch1(int pitch, bool addFlag)
             if (is.drumset())
                   is.setDrumNote(pitch);
             }
+
+      // determine actual pitch and tcp according to note input method and context (if required)
+      //
+      //    TODO : most or all of this process could be moved to separate functions
+      //
+      //    Note: the code below is ready for a 3-level input method (no accidentals at all,
+      //          key accidentals only, key + measure context accidentals) according to the value of
+      //          some global value (InputState::noteInputMethod is used as a place holder);
+      //          level selection statements are commented out
+
+      int   line  = (pitch / 12) * 7 + step;          // compute 'line' (octave*7 + step)
+      int   tpc   = pitch2tpc(pitch);                 // get default tpc (without any accidental)
+
+      if(!drumSet && step != STEP_NONE) {
+//            if(is.noteInputMethod() != NOTEINPUTMETHOD_NONE) {
+                  // take into account accidentals in current key signature
+                  // current tpc value is for a note without accidentals => in the 13 - 19 range (F - B)
+                  KeySigEvent key   = _score->staff(is.track() / VOICES)->keymap()->key(is.tick());
+                  int keyType       = key.accidentalType();
+                  // if keyType == 0 (no accidentals), do nothing
+                  // if key has flats...
+                  if(keyType < 0) {                   // ...our note will be flattened
+                        if(tpc >= 20 + keyType) {     // if its tpc is <= tpc of B at most as many steps
+                              pitch--;                // as there are flats in the key
+                              tpc -= 7;
+                              }
+                        }
+                  // if key has sharps...
+                  else if(keyType > 0) {              // ...our note will be sharpened
+                        if(tpc <= 12 + keyType) {     // if its tpc is >= tpc of F at most as many steps
+                              pitch++;                // as there are sharps in the key
+                              tpc += 7;
+                              }
+                        }
+//                  if(is.noteInputMethod() != NOTEINPUTMMETHOD_KEYSIGONLY) {
+                        // take into account accidentals in previous notes on same line (same measure)
+                        Chord *     chord;
+                        Element *   elem;
+                        // from 1st chord/rest segment of current measure
+                        Measure *   m =         is.segment()->measure();
+                        Segment *   segm =      m->firstCRSegment();
+                        int         fromTrack   = (is.track() / VOICES) * VOICES;
+                        int         toTrack     = fromTrack + VOICES;
+                        // scan ChordRest segments up to current input tick
+                        while(segm->tick() < is.tick()) {
+                              // look in each track of the current input staff
+                              for(int i = fromTrack; i < toTrack; i++) {
+                                    // if element exists and is a chord, check all its notes
+                                    if( (elem=segm->element(i)) != 0 && elem->type() == CHORD) {
+                                          chord = static_cast<Chord*>(elem);
+                                          foreach(Note * note, chord->notes()) {
+                                                // if chord note is in the same line as input note...
+                                                if( tpc2step(note->tpc()) + (note->pitch() / 12) * 7 == line) {
+                                                      // ...use its pitch and tpc
+                                                      pitch = note->pitch();
+                                                      tpc = note->tpc();
+                                                      }
+                                                }
+                                          }
+                                    }
+                              segm = segm->next(SegGrace | SegChordRest);
+                              }
+//                        }
+//                  }
+            }
+
       if (noteEntryMode()) {
             Note* note = _score->addPitch(pitch, addFlag);
             if (note) {
+                  // if Score::addPitch() thought of a different tpc, force note tpc to our value
+                  if(!drumSet && step != STEP_NONE && tpc != note->tpc()) {
+                        // passing the same line as the note currently has will force it
+                        // to be recomputed, if pitch and/or tpc are different
+                        _score->undoChangePitch(note, pitch, tpc, note->line());
+                        }
                   mscore->play(note->chord());
                   adjustCanvasPosition(note, false);
                   }
             }
+      // not sure this 'else' is ever executed: test in line 5232 entered entry mode, if it was not active already
       else {
             Element* e = _score->selection().element();
             if (e && e->type() == NOTE) {
                   Note* note = static_cast<Note*>(e);
-                  Chord* chord = note->chord();
-                  int key = _score->staff(chord->staffIdx())->key(chord->segment()->tick()).accidentalType();
-                  int newTpc = pitch2tpc(pitch, key);
-                  _score->undoChangePitch(note, pitch, newTpc, note->line()/*, note->fret(), note->string()*/);
+//                  Chord* chord = note->chord();
+//                  int key = _score->staff(chord->staffIdx())->key(chord->segment()->tick()).accidentalType();
+//                  int newTpc = pitch2tpc(pitch, key);
+//                  _score->undoChangePitch(note, pitch, newTpc, note->line());
+                  // we already computed right pitch and tpc
+                  _score->undoChangePitch(note, pitch, tpc, note->line());
                   }
             }
       _score->endCmd();

------------------------------ mscore/scoreview.h ------------------------------
index e670223..9598bec 100644
@@ -238,7 +238,7 @@ class ScoreView : public QWidget, public MuseScoreView {
       void figuredBassEndEdit();
       void cmdInsertNote(int note);
       void cmdAddPitch(int note, bool addFlag);
-      void cmdAddPitch1(int, bool);
+      void cmdAddPitch1(int, bool, int step);
       void cmdAddChordName();
       void cmdAddText(int style);
       void cmdEnterRest(const TDuration&);

