Arnout Engelen wrote:
> I'm willing to give this a shot, but I'd like to discuss it here first, and 
> of course I will put any patch up for review first before committing.
>   
As promised: this seems to work well here, if you don't see any problems
with it I'll commit it for broader testing ;).


Arnout
Index: /home/arnouten/workspaces/rosegarden/rosegarden/src/base/NotationTypes.cpp
===================================================================
--- /home/arnouten/workspaces/rosegarden/rosegarden/src/base/NotationTypes.cpp	(revision 8018)
+++ /home/arnouten/workspaces/rosegarden/rosegarden/src/base/NotationTypes.cpp	(working copy)
@@ -586,6 +586,38 @@
     return NoAccidental;
 }
 
+Accidental Key::getAccidentalForStep(int step) const
+{
+	if (isMinor())
+	{
+		step = (step + 5) % 7;
+	}
+	
+	int accidentalCount = getAccidentalCount();
+	
+	if (accidentalCount == 0)
+	{
+		return NoAccidental;
+	}
+
+	bool sharp = isSharp();
+	
+	int currentAccidentalPosition = sharp ? 6 : 3;
+
+	for (int i = 1; i <= accidentalCount; i++)
+	{
+		if (step == currentAccidentalPosition)
+		{
+			return sharp ? Sharp : Flat;
+		}
+		
+		currentAccidentalPosition = 
+			(currentAccidentalPosition + (sharp ? 3 : 4)) % 7;  
+	}
+	
+	return NoAccidental;
+}
+
 vector<int> Key::getAccidentalHeights(const Clef &clef) const
 {
     // staff positions of accidentals
@@ -938,51 +970,120 @@
     return e;
 }
 
+bool
+pitchInKey(int pitch, const Key& key)
+{
+	int pitchOffset = (pitch - key.getTonicPitch() + 12) % 12;
+	
+	static int pitchInMajor[] =
+		{ true, false, true, false, true, true, false, true, false, true, false, true };
+	static int pitchInMinor[] =
+		{ true, false, true, true, false, true, false, true, true, false, true, false };
+	
+	if (key.isMinor())
+	{
+		return pitchInMinor[pitchOffset];
+	}
+	else
+	{
+		return pitchInMajor[pitchOffset];
+	} 
+}
 
 /**
- * Converts performance pitch to height on staff + correct accidentals
- * for current key.
- *
- * This method takes a Clef, Key, Accidental and raw performance pitch, then
- * applies this information to return a height on staff value and an
- * accidental state.  The pitch itself contains a lot of information, but we
- * need to use the Key and user-specified Accidental to make an accurate
- * decision just where to put it on the staff, and what accidental it should
- * display for (or against) the key.
- *
- * This function originally written by Chris Cannam for Rosegarden 2.1
- * Entirely rewritten by Chris Cannam for Rosegarden 4
- * Entirely rewritten by Hans Kieserman
- * Entirely rewritten by Michael McIntyre
- * This version by Michael McIntyre <[EMAIL PROTECTED]>
+ * @param pitch in the range 0..11 (C..B)
+ * 
+ * @author Arnout Engelen
+ */
+Accidental
+resolveNoAccidental(int pitch,
+			      const Key &key,
+			      NoAccidentalStrategy noAccidentalStrategy) 
+{
+	Accidental outputAccidental = "";
+	
+	// Find out the accidental to use, based on the strategy specified
+	switch (noAccidentalStrategy)
+	{
+		case UseKeySharpness:
+			noAccidentalStrategy = 
+				key.isSharp() ? UseSharps : UseFlats;
+			// fall though
+		case UseFlats:
+			// shares code with UseSharps
+		case UseSharps:
+			if (pitchInKey(pitch, key))
+			{
+				outputAccidental = NoAccidental;
+			}
+			else
+			{
+				if (noAccidentalStrategy == UseSharps)
+				{
+					outputAccidental = Sharp;					
+				}	
+				else
+				{
+					outputAccidental = Flat;
+				}
+			}
+			break;
+		case UseKey:
+			// the distance of the pitch from the tonic of the current
+			//  key
+			int pitchOffset = (pitch - key.getTonicPitch() + 12) % 12;
+			// 0: major, 1: minor
+			int minor = key.isMinor();
+			static int pitchToHeight[2][12] =
+				{
+					{ 0, 0, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6 },
+					// a ., b, c, ., d, ., e, f, ., g, . 
+					{ 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6 } //TODO
+				};
+			
+			// map pitchOffset to the extra correction, on top of any 
+			// accidentals in the key. Example: in F major, with a pitchOffset
+			// of 6, the resulting height would be 3 (Bb) and the correction
+			// would be +1, so the resulting note would be B-natural
+			static int pitchToCorrection[2][12] =
+				{
+					{ 0, +1, 0, -1, 0, 0, +1, 0, -1, 0, -1, 0 },
+					{ 0, -1, 0, 0, +1, 0, -1, 0, 0, +1, 0, +1 } //TODO
+				}; 
+			
+			int correction = pitchToCorrection[minor][pitchOffset];
+
+			// Get the accidental normally associated with this height in this
+			//  key.
+			Accidental normalAccidental = key.getAccidentalForStep(pitchToHeight[minor][pitchOffset]);
+	
+			// Apply the pitchCorrection and get the outputAccidental
+			outputAccidental = Accidentals::getAccidental(
+				getPitchOffset(normalAccidental) + correction);
+				
+	}
+	
+	return outputAccidental;
+}
+
+/**
+ * @param pitch in the range 0..11 (C..B)
+ * 
+ * @author Michael McIntyre
  */
 void
-Pitch::rawPitchToDisplayPitch(int rawpitch,
+resolveSpecifiedAccidental(int pitch,
 			      const Clef &clef,
 			      const Key &key,
 			      int &height,
-			      Accidental &accidental) 
+			      int &octave,
+			      Accidental &inputAccidental,
+			      Accidental &outputAccidental)
 {
-
-    // 1. Calculate the octave (for later):
-    int octave = rawpitch / 12;
-
-    // 2. Set initial height to 0
-    height = 0;
-
-    // 3.  Calculate raw semitone number, yielding a value between 0 (C) and
-    // 11 (B)
-    int pitch  = rawpitch % 12;
-
-    // 4.  Get info from the Key
+	// 4.  Get info from the Key
     long accidentalCount = key.getAccidentalCount();
     bool keyIsSharp = key.isSharp(), keyIsFlat = !keyIsSharp;
-    Accidental userAccidental = accidental;
-
-    // clear the in-coming accidental so we can trap any failure to re-set
-    // it on the way out:
-    accidental = "";
-
+    
     // Calculate the flags needed for resolving accidentals against the key.
     // First we initialize them false...
     bool keyHasSharpC = false, keyHasSharpD = false, keyHasSharpE = false,
@@ -1074,74 +1175,74 @@
     // Here we do the actual work of making all the decisions explained above.
     switch (pitch) {
         case 0 : 
-                 if (userAccidental == Sharp ||                         // B#
-                    (userAccidental == NoAccidental && keyHasSharpB)) {
+                 if (inputAccidental == Sharp ||                         // B#
+                    (inputAccidental == NoAccidental && keyHasSharpB)) {
                      height = B;
                      octave--;
-                     accidental = (keyHasSharpB) ? NoAccidental : Sharp;
-                 } else if (userAccidental == DoubleFlat) {             // Dbb
+                     outputAccidental = (keyHasSharpB) ? NoAccidental : Sharp;
+                 } else if (inputAccidental == DoubleFlat) {             // Dbb
                      height = D;
-                     accidental = DoubleFlat;
+                     outputAccidental = DoubleFlat;
                  } else {
                      height = C;                                        // C or C-Natural
-                     accidental = (keyHasFlatC || keyHasSharpC ||
+                     outputAccidental = (keyHasFlatC || keyHasSharpC ||
                                    (keyHasSharpB &&
-                                  userAccidental == Natural)) ? Natural : NoAccidental;
+                                  inputAccidental == Natural)) ? Natural : NoAccidental;
                  }
                  break;
         case 1 : 
-                 if (userAccidental == Sharp ||                       // C#
-                    (userAccidental == NoAccidental &&  keyIsSharp)) {
+                 if (inputAccidental == Sharp ||                       // C#
+                    (inputAccidental == NoAccidental &&  keyIsSharp)) {
                      height = C;
-                     accidental = (keyHasSharpC) ?  NoAccidental : Sharp;
-                 } else if (userAccidental == Flat ||                 // Db
-                           (userAccidental == NoAccidental && keyIsFlat)) {
+                     outputAccidental = (keyHasSharpC) ?  NoAccidental : Sharp;
+                 } else if (inputAccidental == Flat ||                 // Db
+                           (inputAccidental == NoAccidental && keyIsFlat)) {
                      height = D;
-                     accidental = (keyHasFlatD) ? NoAccidental : Flat;
-                 } else if (userAccidental == DoubleSharp) {          // Bx
+                     outputAccidental = (keyHasFlatD) ? NoAccidental : Flat;
+                 } else if (inputAccidental == DoubleSharp) {          // Bx
                     height = B;
                     octave--;
-                    accidental = DoubleSharp;
+                    outputAccidental = DoubleSharp;
                  }
                  break;
         case 2 : 
-                 if (userAccidental == DoubleSharp) {                  // Cx
+                 if (inputAccidental == DoubleSharp) {                  // Cx
                      height = C;
-                     accidental = DoubleSharp;
-                 } else if (userAccidental == DoubleFlat) {            // Ebb
+                     outputAccidental = DoubleSharp;
+                 } else if (inputAccidental == DoubleFlat) {            // Ebb
                      height = E;
-                     accidental = DoubleFlat;
+                     outputAccidental = DoubleFlat;
                  } else {                                              // D or D-Natural
                      height = D;
-                     accidental = (keyHasSharpD || keyHasFlatD) ? Natural : NoAccidental;
+                     outputAccidental = (keyHasSharpD || keyHasFlatD) ? Natural : NoAccidental;
                  }
                  break;
         case 3 : 
-                 if (userAccidental == Sharp ||                        // D#
-                    (userAccidental == NoAccidental &&  keyIsSharp)) {
+                 if (inputAccidental == Sharp ||                        // D#
+                    (inputAccidental == NoAccidental &&  keyIsSharp)) {
                      height = D;
-                     accidental = (keyHasSharpD) ? NoAccidental : Sharp;
-                 } else if (userAccidental == Flat ||                  // Eb
-                           (userAccidental == NoAccidental &&  keyIsFlat)) {
+                     outputAccidental = (keyHasSharpD) ? NoAccidental : Sharp;
+                 } else if (inputAccidental == Flat ||                  // Eb
+                           (inputAccidental == NoAccidental &&  keyIsFlat)) {
                      height = E;
-                     accidental = (keyHasFlatE) ? NoAccidental : Flat;
-                 } else if (userAccidental == DoubleFlat) {            // Fbb
+                     outputAccidental = (keyHasFlatE) ? NoAccidental : Flat;
+                 } else if (inputAccidental == DoubleFlat) {            // Fbb
                      height = F;
-                     accidental = DoubleFlat;
+                     outputAccidental = DoubleFlat;
                  }
                  break;
         case 4 : 
-                 if (userAccidental == Flat ||                         // Fb
-                    (userAccidental == NoAccidental && keyHasFlatF)) {
+                 if (inputAccidental == Flat ||                         // Fb
+                    (inputAccidental == NoAccidental && keyHasFlatF)) {
                      height = F;
-                     accidental = (keyHasFlatF) ? NoAccidental : Flat;
-                 } else if (userAccidental == DoubleSharp) {           // Dx
+                     outputAccidental = (keyHasFlatF) ? NoAccidental : Flat;
+                 } else if (inputAccidental == DoubleSharp) {           // Dx
                      height = D;
-                     accidental = DoubleSharp;
+                     outputAccidental = DoubleSharp;
                  } else {                                              // E or E-Natural
                      height = E;
-                     accidental = (keyHasSharpE || keyHasFlatE ||
-                                   (keyHasFlatF && userAccidental==Natural)) ?
+                     outputAccidental = (keyHasSharpE || keyHasFlatE ||
+                                   (keyHasFlatF && inputAccidental==Natural)) ?
                                     Natural : NoAccidental;
                  }
                  break;
@@ -1146,17 +1247,17 @@
                  }
                  break;
         case 5 : 
-                 if (userAccidental == Sharp ||                        // E#
-                    (userAccidental == NoAccidental && keyHasSharpE)) {
+                 if (inputAccidental == Sharp ||                        // E#
+                    (inputAccidental == NoAccidental && keyHasSharpE)) {
                      height = E;
-                     accidental = (keyHasSharpE) ? NoAccidental : Sharp;
-                 } else if (userAccidental == DoubleFlat) {            // Gbb
+                     outputAccidental = (keyHasSharpE) ? NoAccidental : Sharp;
+                 } else if (inputAccidental == DoubleFlat) {            // Gbb
                      height = G;
-                     accidental = DoubleFlat;
+                     outputAccidental = DoubleFlat;
                  } else {                                              // F or F-Natural
                      height = F;
-                     accidental = (keyHasSharpF || keyHasFlatF ||
-                                   (keyHasSharpE && userAccidental==Natural))?
+                     outputAccidental = (keyHasSharpF || keyHasFlatF ||
+                                   (keyHasSharpE && inputAccidental==Natural))?
                                     Natural : NoAccidental;
                  }
                  break;
@@ -1161,82 +1262,82 @@
                  }
                  break;
         case 6 : 
-                 if (userAccidental == Sharp ||
-                    (userAccidental == NoAccidental && keyIsSharp)) {  // F#
+                 if (inputAccidental == Sharp ||
+                    (inputAccidental == NoAccidental && keyIsSharp)) {  // F#
                      height = F;
-                     accidental = (keyHasSharpF) ? NoAccidental : Sharp;
-                 } else if (userAccidental == Flat ||                  // Gb
-                           (userAccidental == NoAccidental && keyIsFlat)) {
+                     outputAccidental = (keyHasSharpF) ? NoAccidental : Sharp;
+                 } else if (inputAccidental == Flat ||                  // Gb
+                           (inputAccidental == NoAccidental && keyIsFlat)) {
                      height = G;
-                     accidental = (keyHasFlatG) ? NoAccidental : Flat;
-                 } else if (userAccidental == DoubleSharp) {           // Ex
+                     outputAccidental = (keyHasFlatG) ? NoAccidental : Flat;
+                 } else if (inputAccidental == DoubleSharp) {           // Ex
                      height = E;
-                     accidental = DoubleSharp;
+                     outputAccidental = DoubleSharp;
                  }
                  break;
         case 7 : 
-                 if (userAccidental == DoubleSharp) {                  // Fx
+                 if (inputAccidental == DoubleSharp) {                  // Fx
                      height = F;
-                     accidental = DoubleSharp;
-                 } else if (userAccidental == DoubleFlat) {            // Abb
+                     outputAccidental = DoubleSharp;
+                 } else if (inputAccidental == DoubleFlat) {            // Abb
                      height = A;
-                     accidental = DoubleFlat;
+                     outputAccidental = DoubleFlat;
                  } else {                                              // G or G-Natural
                      height = G;
-                     accidental = (keyHasSharpG || keyHasFlatG) ? Natural : NoAccidental;
+                     outputAccidental = (keyHasSharpG || keyHasFlatG) ? Natural : NoAccidental;
                  }
                  break;
         case 8 : 
-                 if (userAccidental == Sharp ||
-                    (userAccidental == NoAccidental && keyIsSharp)) {  // G#
+                 if (inputAccidental == Sharp ||
+                    (inputAccidental == NoAccidental && keyIsSharp)) {  // G#
                      height = G;
-                     accidental = (keyHasSharpG) ? NoAccidental : Sharp;
-                 } else if (userAccidental == Flat ||                  // Ab
-                           (userAccidental == NoAccidental && keyIsFlat)) {
+                     outputAccidental = (keyHasSharpG) ? NoAccidental : Sharp;
+                 } else if (inputAccidental == Flat ||                  // Ab
+                           (inputAccidental == NoAccidental && keyIsFlat)) {
                      height = A;
-                     accidental = (keyHasFlatA) ? NoAccidental : Flat;
+                     outputAccidental = (keyHasFlatA) ? NoAccidental : Flat;
                  }
                  break;
         case 9 :
-                 if (userAccidental == DoubleSharp) {                  // Gx
+                 if (inputAccidental == DoubleSharp) {                  // Gx
                      height = G;
-                     accidental = DoubleSharp;
-                 } else if (userAccidental == DoubleFlat) {            // Bbb
+                     outputAccidental = DoubleSharp;
+                 } else if (inputAccidental == DoubleFlat) {            // Bbb
                      height = B;
-                     accidental = DoubleFlat;
+                     outputAccidental = DoubleFlat;
                  } else {                                              // A or A-Natural
                      height = A;                
-                     accidental = (keyHasSharpA || keyHasFlatA) ? Natural : NoAccidental;
+                     outputAccidental = (keyHasSharpA || keyHasFlatA) ? Natural : NoAccidental;
                  }
                  break;
         case 10: 
-                 if (userAccidental == DoubleFlat) {                   // Cbb
+                 if (inputAccidental == DoubleFlat) {                   // Cbb
                      height = C;
                      octave++;  // tweak B/C divide
-                     accidental = DoubleFlat;
-                 } else if (userAccidental == Sharp ||                 // A#
-                           (userAccidental == NoAccidental && keyIsSharp)) {
+                     outputAccidental = DoubleFlat;
+                 } else if (inputAccidental == Sharp ||                 // A#
+                           (inputAccidental == NoAccidental && keyIsSharp)) {
                      height = A;
-                     accidental = (keyHasSharpA) ? NoAccidental : Sharp;
-                 } else if (userAccidental == Flat ||                  // Bb
-                           (userAccidental == NoAccidental && keyIsFlat)) {
+                     outputAccidental = (keyHasSharpA) ? NoAccidental : Sharp;
+                 } else if (inputAccidental == Flat ||                  // Bb
+                           (inputAccidental == NoAccidental && keyIsFlat)) {
                      height = B;
-                     accidental = (keyHasFlatB) ? NoAccidental : Flat;
+                     outputAccidental = (keyHasFlatB) ? NoAccidental : Flat;
                  }
                  break;
         case 11: 
-                 if (userAccidental == DoubleSharp) {                  // Ax
+                 if (inputAccidental == DoubleSharp) {                  // Ax
                      height = A;
-                     accidental = DoubleSharp;
-                 } else if (userAccidental == Flat ||                  // Cb
-                           (userAccidental == NoAccidental && keyHasFlatC)) {
+                     outputAccidental = DoubleSharp;
+                 } else if (inputAccidental == Flat ||                  // Cb
+                           (inputAccidental == NoAccidental && keyHasFlatC)) {
                      height = C;
                      octave++;  // tweak B/C divide
-                     accidental = (keyHasFlatC) ? NoAccidental : Flat;
+                     outputAccidental = (keyHasFlatC) ? NoAccidental : Flat;
                  } else {                                             // B or B-Natural
                      height = B;
-                     accidental = (keyHasSharpB || keyHasFlatB ||
-                                   (keyHasFlatC && userAccidental==Natural)) ?
+                     outputAccidental = (keyHasSharpB || keyHasFlatB ||
+                                   (keyHasFlatC && inputAccidental==Natural)) ?
                                     Natural : NoAccidental;
                  }
     }
@@ -1241,10 +1342,108 @@
                  }
     }
 
-    if (accidental == NoAccidental && userAccidental == Natural) {
-	accidental = Natural;
+    if (outputAccidental == NoAccidental && inputAccidental == Natural) {
+	outputAccidental = Natural;
     }
+	
+}
+
+bool 
+Pitch::validAccidental() const
+{
+//	std::cout << "Checking whether accidental is valid " << std::endl;
+	if (m_accidental == NoAccidental)
+	{
+		return true;
+	}
+	int naturalPitch = (m_pitch - 
+		Accidentals::getPitchOffset(m_accidental) + 12) % 12;
+	switch(naturalPitch)
+	{
+		case 0: //C
+			return true;
+		case 1:
+			return false;
+		case 2: //D
+			return true;
+		case 3:
+			return false;
+		case 4: //E
+			return true;
+		case 5: //F
+			return true;
+		case 6:
+			return false;
+		case 7: //G
+			return true;
+		case 8:
+			return false;
+		case 9: //A
+			return true;
+		case 10:
+			return false;
+		case 11: //B
+			return true;
+	};
+	std::cout << "Internal error in validAccidental" << std::endl;
+	return false;
+}
+
+/**
+ * Converts performance pitch to height on staff + correct accidentals
+ * for current key.
+ *
+ * This method takes a Clef, Key, Accidental and raw performance pitch, then
+ * applies this information to return a height on staff value and an
+ * accidental state.  The pitch itself contains a lot of information, but we
+ * need to use the Key and user-specified Accidental to make an accurate
+ * decision just where to put it on the staff, and what accidental it should
+ * display for (or against) the key.
+ *
+ * This function originally written by Chris Cannam for Rosegarden 2.1
+ * Entirely rewritten by Chris Cannam for Rosegarden 4
+ * Entirely rewritten by Hans Kieserman
+ * Entirely rewritten by Michael McIntyre
+ * This version by Michael McIntyre <[EMAIL PROTECTED]>
+ * Resolving the accidental was refactored out by Arnout Engelen 
+ */
+void
+Pitch::rawPitchToDisplayPitch(int rawpitch,
+			      const Clef &clef,
+			      const Key &key,
+			      int &height,
+			      Accidental &accidental,
+			      NoAccidentalStrategy noAccidentalStrategy) 
+{
+
+    // 1. Calculate the octave (for later):
+    int octave = rawpitch / 12;
+
+    // 2. Set initial height to 0
+    height = 0;
 
+    // 3.  Calculate raw semitone number, yielding a value between 0 (C) and
+    // 11 (B)
+    int pitch  = rawpitch % 12;
+    
+    // clear the in-coming accidental so we can trap any failure to re-set
+    // it on the way out:
+    Accidental userAccidental = accidental;
+    accidental = "";
+    
+    if (userAccidental == NoAccidental || !Pitch(rawpitch, userAccidental).validAccidental())
+    {
+    	userAccidental = resolveNoAccidental(pitch, key, noAccidentalStrategy);
+    	//std::cout << "Chose accidental " << userAccidental << " for pitch " << pitch <<
+    	//	" in key " << key.getName() << std::endl;
+    }
+    //else
+    //{
+    //	std::cout << "Accidental was specified, as " << userAccidental << std::endl;
+    //}
+    
+    resolveSpecifiedAccidental(pitch, clef, key, height, octave, userAccidental, accidental);
+    
     // Failsafe...  If this ever executes, there's trouble to fix...
 // WIP - DMM - munged up to explore #937389, which is temporarily deferred,
 // owing to its non-critical nature, having been hacked around in the Lilypond
@@ -1431,7 +1630,8 @@
 Accidental
 Pitch::getAccidental(bool useSharps) const
 {
-    return getDisplayAccidental(useSharps ? Key("C major") : Key("A minor"));
+    return getDisplayAccidental(Key("C major"), 
+		useSharps ? UseSharps : UseFlats);
 }
 
 Accidental
@@ -1437,32 +1637,17 @@
 Accidental
 Pitch::getAccidental(const Key &key) const
 {
-    // C major means use sharps, A minor means use flats
-    Key testKey = (key.isSharp() ? Key("C major") : Key("A minor"));
-    
-    // compare the note name in its own key against the note name in either C
-    // major or A minor, to see if it differs
-    std::string keyNote = "", rawNote = "";
-    keyNote += getNoteName(key);
-    rawNote += getNoteName(testKey);
-    
-    // if these two notes names don't match, we might have one of the hateful
-    // E#/F E/Fb B#/C B/Cb notes, which are enharmonics that use a *different*
-    // MIDI pitch, so we check for those first, as they will resolve to
-    // different notes/heights depending on their key signature
-    if      (keyNote == "E" && rawNote == "F") // E#
-	return Sharp;
-    else if (keyNote == "F" && rawNote == "E") // Fb
-	return Flat;
-    else if (keyNote == "B" && rawNote == "C") // B#
-	return Sharp;
-    else if (keyNote == "C" && rawNote == "B") // Cb
-	return Flat;
-    else
-    // if it wasn't, we don't really care about other enharmonics, which are
-    // all two notes that share the *same* MIDI pitch, so we just return an
-    // accidental against the caller's stated useSharps preference.
-	return getDisplayAccidental(testKey);
+	if (m_accidental == NoAccidental || !validAccidental())
+	{
+		Accidental retval = resolveNoAccidental(m_pitch, key, UseKey);
+		//std::cout << "Resolved No/invalid accidental: chose " << retval << std::endl;
+		return retval; 
+	}
+	else
+	{
+		//std::cout << "Returning specified accidental" << std::endl;
+		return m_accidental;
+	}
 }
 
 Accidental
@@ -1468,9 +1653,15 @@
 Accidental
 Pitch::getDisplayAccidental(const Key &key) const
 {
+    return getDisplayAccidental(key, UseKey);
+}
+
+Accidental
+Pitch::getDisplayAccidental(const Key &key, NoAccidentalStrategy noAccidentalStrategy) const
+{
     int heightOnStaff;
     Accidental accidental(m_accidental);
-    rawPitchToDisplayPitch(m_pitch, Clef(), key, heightOnStaff, accidental);
+    rawPitchToDisplayPitch(m_pitch, Clef(), key, heightOnStaff, accidental, noAccidentalStrategy);
     return accidental;
 }
 
@@ -1482,7 +1673,7 @@
     p -= Accidentals::getPitchOffset(getDisplayAccidental(key));
     p += 24; // in case these calculations made it -ve
     p %= 12;
-
+    
     static int major[]          = { 0, 0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6 };
     static int minor_harmonic[] = { 0, 0, 1, 2, 2, 3, 3, 4, 5, 5, 5, 6 };
 
@@ -1502,7 +1693,7 @@
 {
     int heightOnStaff;
     Accidental accidental(m_accidental);
-    rawPitchToDisplayPitch(m_pitch, clef, key, heightOnStaff, accidental);
+    rawPitchToDisplayPitch(m_pitch, clef, key, heightOnStaff, accidental, UseKey);
     return heightOnStaff;
 }
 
@@ -1603,6 +1794,7 @@
 	Pitch oldPitchWithoutAccidental(getPerformancePitch() - Accidentals::getPitchOffset(oldAccidental), Natural);
 	Key cmaj = Key();
 	int oldStep = getNoteInScale(cmaj) + oldPitchWithoutAccidental.getOctave(0) * 7;
+	std::cout << "old step: " << oldStep % 7 << std::endl;
 	
 	// calculate new pitch and step
 	int newPitch = getPerformancePitch() + pitchDelta;
@@ -1612,6 +1804,7 @@
 	static int stepIntervals[] = { 0,2,4,5,7,9,11 };
 	int pitchWithoutAccidental = ((newStep / 7) * 12 + stepIntervals[newStep % 7]);
 	int newAccidentalOffset = newPitch - pitchWithoutAccidental;
+	std::cout << "new accidentalOffset: " << newAccidentalOffset << std::endl;
 	// construct pitch-object to return
 	Pitch newPitchObj(newPitch, Accidentals::getAccidental(newAccidentalOffset));
 	return newPitchObj;
Index: /home/arnouten/workspaces/rosegarden/rosegarden/src/base/NotationTypes.h
===================================================================
--- /home/arnouten/workspaces/rosegarden/rosegarden/src/base/NotationTypes.h	(revision 8018)
+++ /home/arnouten/workspaces/rosegarden/rosegarden/src/base/NotationTypes.h	(working copy)
@@ -92,6 +92,23 @@
 
     typedef std::vector<Accidental> AccidentalList;
 
+	/** 
+	 * When no accidental is specified for a pitch, there are several
+	 * strategies to determine what accidental to display for an 
+	 * out-of-key pitch
+	 */
+	enum NoAccidentalStrategy {
+		/** always use sharps */
+		UseSharps,
+		/** always use flats */
+		UseFlats,
+		/** always use sharps or always use flats depending on of what
+		 * type of accidentals the current key is made up */ 
+		UseKeySharpness,
+		/** use the most likely accidental for this key */
+		UseKey
+	};
+
     /**
      * Get the predefined accidentals (i.e. the ones listed above)
      * in their defined order.
@@ -479,6 +496,13 @@
     Accidental getAccidentalAtHeight(int height, const Clef &clef) const;
 
     /**
+     * Return the accidental for the the given number of steps
+     * from the tonic. For example: for F major, step '3' is the
+     * Bb, so getAccidentalForStep(3) will yield a Flat.
+     */
+    Accidental getAccidentalForStep(int steps) const;
+
+    /**
      * Return the heights-on-staff (in Pitch
      * terminology) of all accidentals in the key's signature,
      * in the given clef.
@@ -840,6 +864,13 @@
      */
     Accidental getDisplayAccidental(const Key &key) const;
 
+	/**
+     * Return the accidental that should be used to display this pitch
+     * in a given key, using the given strategy to resolve pitches where
+     * an accidental is needed but not specified.
+     */
+    Accidental getDisplayAccidental(const Key &key, Accidentals::NoAccidentalStrategy) const;
+
     /**
      * Return the position in the scale for this pitch, as a number in
      * the range 0 to 6 where 0 is the root of the key.
@@ -925,6 +956,13 @@
 	 */
 	Pitch transpose(Key key, int pitchDelta, int heightDelta);
 
+	/** 
+ 	 * checks whether the accidental specified for this pitch (if any)
+ 	 * is valid - for example, a Sharp for pitch 11 is invalid, as
+ 	 * it's between A# and B#.
+ 	 */  
+	bool validAccidental() const;
+
 private:
     int m_pitch;
     Accidental m_accidental;
@@ -930,7 +968,8 @@
     Accidental m_accidental;
 
     static void rawPitchToDisplayPitch
-    (int, const Clef &, const Key &, int &, Accidental &);
+    (int, const Clef &, const Key &, int &, Accidental &, 
+    Accidentals::NoAccidentalStrategy);
 
     static void displayPitchToRawPitch
     (int, Accidental, const Clef &, const Key &,
Index: /home/arnouten/workspaces/rosegarden/rosegarden/src/document/io/LilypondExporter.cpp
===================================================================
--- /home/arnouten/workspaces/rosegarden/rosegarden/src/document/io/LilypondExporter.cpp	(revision 8018)
+++ /home/arnouten/workspaces/rosegarden/rosegarden/src/document/io/LilypondExporter.cpp	(working copy)
@@ -1561,8 +1561,7 @@
                 Accidental accidental = Accidentals::NoAccidental;
 
                 std::cout << "key tonic pitch: " << key.getTonicPitch() << std::endl; //REMOVE
-                str << convertPitchToLilyNote(key.getTonicPitch(), accidental,
-                                              key.isSharp() ? Rosegarden::Key ("C major") : Rosegarden::Key ("A minor"));
+                str << convertPitchToLilyNote(key.getTonicPitch(), accidental, key);
 
                 if (key.isMinor()) {
                     str << " \\minor";
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Rosegarden-devel mailing list
[email protected] - use the link below to unsubscribe
https://lists.sourceforge.net/lists/listinfo/rosegarden-devel

Reply via email to