]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/chord.cc
release: 1.3.14
[lilypond.git] / lily / chord.cc
index adef8d4991c5e2f35ab1edd645515c788a6b3212..89d4c4590ede0f1299db3c0a6be06477a4806cbd 100644 (file)
@@ -9,6 +9,10 @@
 #include "chord.hh"
 #include "musical-request.hh"
 #include "warn.hh"
+#include "debug.hh"
+#include "molecule.hh"
+#include "paper-def.hh"
+#include "lookup.hh"
 
 
 /*
@@ -17,7 +21,7 @@
 Chord
 to_chord (Musical_pitch tonic, Array<Musical_pitch>* add_arr_p, Array<Musical_pitch>* sub_arr_p, Musical_pitch* inversion_p, Musical_pitch* bass_p)
 {
-  // urg: catch dim modifier: 5th and 7th should be lowered
+  // urg: catch dim modifier: 3rd, 5th, 7th, .. should be lowered
   bool dim_b = false;
   for (int i=0; i < add_arr_p->size (); i++)
     {
@@ -28,12 +32,10 @@ to_chord (Musical_pitch tonic, Array<Musical_pitch>* add_arr_p, Array<Musical_pi
          dim_b = true;
        }
     }
-  Chord::rebuild_transpose (add_arr_p, tonic);
-  Chord::rebuild_transpose (sub_arr_p, tonic);
+  Chord::rebuild_transpose (add_arr_p, tonic, true);
+  Chord::rebuild_transpose (sub_arr_p, tonic, true);
 
-  Musical_pitch fifth = tonic;
-  fifth.transpose (Musical_pitch (2));
-  fifth.transpose (Musical_pitch (2, -1));
+  Musical_pitch fifth = Chord::base_arr (tonic).top ();
 
   /*
     remove double adds (urg: sus4)
@@ -68,19 +70,21 @@ to_chord (Musical_pitch tonic, Array<Musical_pitch>* add_arr_p, Array<Musical_pi
   if (highest_step < 5)
     missing_arr.push (fifth);
 
+  /*
+    if dim modifier is given: lower all missing
+   */
   if (dim_b)
     {
       for (int i=0; i < missing_arr.size (); i++)
         {
-          missing_arr[i].accidental_i_--;
+         missing_arr[i].accidental_i_--;
        }
     }
 
   /*
     if additions include some 3, don't add third
    */
-  Musical_pitch third = tonic;
-  third.transpose (Musical_pitch (2));
+  Musical_pitch third = Chord::base_arr (tonic)[1];
   if (Chord::find_notename_i (add_arr_p, third) != -1)
     {
       int i = Chord::find_pitch_i (&missing_arr, third);
@@ -192,37 +196,64 @@ to_chord (Array<Musical_pitch> pitch_arr, Tonic_req* tonic_req, Inversion_req* i
   return Chord (pitch_arr, inversion_p, bass_p);
 }
 
+Chord::Chord ()
+{
+  inversion_b_ = false;
+  bass_b_ = false;
+}
+
 Chord::Chord (Array<Musical_pitch> pitch_arr, Musical_pitch* inversion_p, Musical_pitch* bass_p)
 {
   pitch_arr_ = pitch_arr;
-  inversion_p_ = inversion_p;
-  bass_p_ = bass_p;
+  inversion_b_ = false;
+  bass_b_ = false;
+  if (inversion_p)
+    {
+      inversion_pitch_ = *inversion_p;
+      inversion_b_ = true;
+      delete inversion_p;
+    }
+  if (bass_p)
+    {
+      bass_pitch_ = *bass_p;
+      bass_b_ = true;
+      delete bass_p;
+    }
 }
-
+  
 Chord::Chord (Chord const& chord)
 {
   pitch_arr_ = chord.pitch_arr_;
-  inversion_p_ = chord.inversion_p_ ? new Musical_pitch (*chord.inversion_p_) : 0;
-  bass_p_ = chord.bass_p_ ? new Musical_pitch (*chord.bass_p_) : 0;
+  inversion_b_ = chord.inversion_b_;
+  inversion_pitch_ = chord.inversion_pitch_;
+  bass_b_ = chord.bass_b_;
+  bass_pitch_ = chord.bass_pitch_;
 }
+  
 
-Chord::~Chord ()
+Array<Musical_pitch>
+Chord::base_arr (Musical_pitch p)
 {
-  delete inversion_p_;
-  delete bass_p_;
+  Array<Musical_pitch> base;
+  base.push (p);
+  p.transpose (Musical_pitch (2));
+  base.push (p);
+  p.transpose (Musical_pitch (2, -1));
+  base.push (p);
+  return base;
 }
 
 void
-Chord::rebuild_transpose (Array<Musical_pitch>* pitch_arr_p, Musical_pitch tonic)
+Chord::rebuild_transpose (Array<Musical_pitch>* pitch_arr_p, Musical_pitch tonic, bool fix7_b)
 {
   for (int i = 0; i < pitch_arr_p->size (); i++)
     {
       Musical_pitch p = tonic;
       Musical_pitch q = (*pitch_arr_p)[i];
-      // duh, c7 should mean <c bes>
-      if (q.notename_i_ == 6)
-        q.accidental_i_--;
       p.transpose (q);
+      // duh, c7 should mean <c bes>
+      if (fix7_b && (step_i (tonic, p) == 7))
+        p.accidental_i_--;
       (*pitch_arr_p)[i] = p;
     }
   pitch_arr_p->sort (Musical_pitch::compare);
@@ -320,51 +351,55 @@ Array<Musical_pitch>
 Chord::to_pitch_arr () const
 {
   Array<Musical_pitch> pitch_arr = pitch_arr_;
-  if (inversion_p_)
+  if (inversion_b_)
     {
       int i = 0;
       for (; i < pitch_arr.size (); i++)
        {
-         if ((pitch_arr[i].notename_i_ == inversion_p_->notename_i_)
-             && (pitch_arr[i].accidental_i_ == inversion_p_->accidental_i_))
+         if ((pitch_arr[i].notename_i_ == inversion_pitch_.notename_i_)
+             && (pitch_arr[i].accidental_i_ == inversion_pitch_.accidental_i_))
            break;
        }
       if (i == pitch_arr.size ())
        {
          warning (_f ("invalid inversion pitch: not part of chord: %s",
-                      inversion_p_->str ()));
+                      inversion_pitch_.str ()));
        }
       else
        rebuild_with_bass (&pitch_arr, i);
     }
 
-  if (bass_p_)
+  if (bass_b_)
     {
-      pitch_arr.insert (*bass_p_, 0);
+      pitch_arr.insert (bass_pitch_, 0);
       rebuild_with_bass (&pitch_arr, 0);
     }
   return pitch_arr;
 }
 
 void
-Chord::find_additions_and_subtractions (Array<Musical_pitch>* add_arr_p, Array<Musical_pitch>* sub_arr_p) const
+Chord::find_additions_and_subtractions (Array<Musical_pitch> pitch_arr, Array<Musical_pitch>* add_arr_p, Array<Musical_pitch>* sub_arr_p)
 {
-  Musical_pitch tonic = pitch_arr_[0];
+  Musical_pitch tonic = pitch_arr[0];
   /*
     construct an array of thirds for a normal chord
    */
   Array<Musical_pitch> all_arr;
   all_arr.push (tonic);
-  all_arr.push (pitch_arr_.top ());
+  if (step_i (tonic, pitch_arr.top ()) >= 5)
+    all_arr.push (pitch_arr.top ());
+  else
+    all_arr.push (base_arr (tonic).top ());
   all_arr.concat (missing_thirds_pitch_arr (&all_arr));
   all_arr.sort (Musical_pitch::compare);
   
   int i = 0;
   int j = 0;
-  while ((i < all_arr.size ()) || (j < pitch_arr_.size ()))
+  Musical_pitch last_extra = tonic;
+  while ((i < all_arr.size ()) || (j < pitch_arr.size ()))
     {
       Musical_pitch a = all_arr [i <? all_arr.size () - 1];
-      Musical_pitch p = pitch_arr_ [j <? pitch_arr_.size () - 1];
+      Musical_pitch p = pitch_arr[j <? pitch_arr.size () - 1];
       /*
         this pitch is present: do nothing, check next
        */
@@ -372,6 +407,7 @@ Chord::find_additions_and_subtractions (Array<Musical_pitch>* add_arr_p, Array<M
        {
          i++;
          j++;
+         last_extra = tonic;
        }
       /*
         found an extra pitch: chord addition
@@ -379,166 +415,44 @@ Chord::find_additions_and_subtractions (Array<Musical_pitch>* add_arr_p, Array<M
       else if ((p < a) || (p.notename_i_ == a.notename_i_))
        {
          add_arr_p->push (p);
-         (j < pitch_arr_.size ()) ? j++ : i++;
+         last_extra = p;
+         (j < pitch_arr.size ()) ? j++ : i++;
        }
       /*
         a third is missing: chord subtraction
        */
       else
        {
-         sub_arr_p->push (a);
+         if (last_extra.notename_i_ != a.notename_i_)
+           sub_arr_p->push (a);
          (i < all_arr.size ()) ? i++ : j++;
+         last_extra = tonic;
        }
     }
       
+  /* add missing basic steps */
+  if (step_i (tonic, pitch_arr.top ()) < 3)
+    sub_arr_p->push (base_arr (tonic)[1]);
+  if (step_i (tonic, pitch_arr.top ()) < 5)
+    sub_arr_p->push (base_arr (tonic).top ());
+
   /*
-    add highest addition, because it names chord
-    (1, 3 and) 5 not an addition: part of normal chord
+    add highest addition, because it names chord, if greater than 5
+    or non-standard
+    (1, 3 and) 5 not additions: part of normal chord
    */
-  if (step_i (tonic, pitch_arr_.top () > 5))
-    add_arr_p->push (pitch_arr_.top ());
+  if ((step_i (tonic, pitch_arr.top ()) > 5)
+       || pitch_arr.top ().accidental_i_)
+    add_arr_p->push (pitch_arr.top ());
 }
 
+
 /*
-  TODO:
-   reduce guess work: dim chord
-   other naming conventions `American'?
-   don't use TeX constructs
-   user defined chords-names for specific chords:
-      tonic, additions, subtractions, inversion, bass -> "my-chord-name"
+  This routine tries to guess tonic in a possibly inversed chord, ie
+  <e g c'> should produce: C.
+  This is only used for chords that are entered as simultaneous notes,
+  chords entered in \chord mode are fully defined.
  */
-String
-Chord::banter_str () const
-{
-  Musical_pitch tonic = pitch_arr_[0];
-
-  //urg, should do translation in scheme.
-  char const *acc[] = {"\\textflat\\textflat ", "\\textflat ", "", "\\textsharp " , "\\textsharp\\textsharp "};
-  String tonic_str = tonic.str ();
-  tonic_str = tonic_str.left_str (1).upper_str ()
-    + acc[tonic.accidental_i_ + 2];
-
-  Array<Musical_pitch> add_arr;
-  Array<Musical_pitch> sub_arr;
-  find_additions_and_subtractions (&add_arr, &sub_arr);
-                          
-
-  Array<Musical_pitch> scale;
-  for (int i=0; i < 7; i++)
-    scale.push (Musical_pitch (i));
-
-  // 7 always means 7-...
-  //  scale.push (Musical_pitch (6, -1)); // b
-
-  rebuild_transpose (&scale, tonic);
-  
-  bool has3m_b = false;
-  bool has4_b = false;
-  bool has5m_b = false;
-  String str;
-  String minor_str;
-  String sep_str;
-  for (int i = 0; i < add_arr.size (); i++)
-    {
-      Musical_pitch p = add_arr[i];
-      int step = step_i (tonic, p);
-      if (step == 4)
-       has4_b = true;
-      int accidental = p.accidental_i_ - scale[(step - 1) % 7].accidental_i_;
-      if ((step == 3) && (accidental == -1))
-       {
-         minor_str = "m";
-         has3m_b = true;
-       }
-      /*
-       have Cdim rather than Cm5-, even if it's a prefix
-       */
-      else if ((step == 5) && (accidental == -1) && has3m_b)
-       {
-         minor_str = "dim";
-         has5m_b = true;
-       }
-      else if (accidental
-              || (!(step % 2) || ((i + 1 == add_arr.size ()) && (step > 5))))
-        {
-         str += sep_str;
-         sep_str = "/";
-          if ((step == 7) && (accidental == 1))
-           {
-              str += "maj7";
-           }
-         else
-            {
-             /* 
-               if has3m_b and has5m_b, assume dim
-               don't mention dim-addition, except for chord-namer
-              */
-              if (((step/2) && (accidental == -1))
-                 && has3m_b && has5m_b)
-               {
-                 if (i == add_arr.size () - 1)
-                    str += to_str (step);
-                 else
-                   sep_str = "";
-               }
-             else
-               {
-                  str += to_str (step);
-                  if (accidental)
-                    str += accidental < 0 ? "-" : "+";
-               }
-            }
-       }
-    }
-
-  for (int i = 0; i < sub_arr.size (); i++)
-    {
-      Musical_pitch p = sub_arr[i];
-      int step = step_i (tonic, p);
-      /*
-       if chord has 3-, assume minor and don't display 'no3'
-       if additions include 4, assume sus4 and don't display 'no3'
-       if has3m_b and has5m_b, assume 'dim' chord
-      */
-      if (!((step == 3) && (has3m_b || has4_b))
-         && !((step/2) && (step !=3) && (step !=7 ) && (p.accidental_i_ == 0) && has3m_b && has5m_b)
-         && !((step == 7) && (p.accidental_i_ == -1) && has3m_b && has5m_b))
-       {
-         str += sep_str + "no" + to_str (step);
-         sep_str = "/";
-       }
-    }
-
-  /*
-   have Co rather than Cdim7
-   */
-  if (minor_str + str == "dim7")
-    {
-      minor_str = "";
-      str = "o";
-    }
-    
-
-  String inversion_str;
-  if (inversion_p_)
-    {
-      inversion_str = inversion_p_->str ();
-      inversion_str = "/" + inversion_str.left_str (1).upper_str ()
-       + acc[inversion_p_->accidental_i_ + 2];
-    }
-
-  String bass_str;
-  if (bass_p_)
-    {
-      bass_str = bass_p_->str ();
-      bass_str = "/" + bass_str.left_str (1).upper_str ()
-       + acc[bass_p_->accidental_i_ + 2];
-
-    }
-
-  return tonic_str + minor_str + "$^{" + str + "}$" + inversion_str + bass_str;
-}
-
 int
 Chord::find_tonic_i (Array<Musical_pitch> const* pitch_arr_p)
 {
@@ -648,3 +562,4 @@ Chord::rebuild_with_bass (Array<Musical_pitch>* pitch_arr_p, int bass_i)
       bass.octave_i_--;
   pitch_arr_p->insert (bass, 0);
 }
+