]> git.donarmstrong.com Git - lilypond.git/commitdiff
lilypond-1.1.27
authorfred <fred>
Tue, 26 Mar 2002 21:46:43 +0000 (21:46 +0000)
committerfred <fred>
Tue, 26 Mar 2002 21:46:43 +0000 (21:46 +0000)
input/test/chord-inversion.ly
input/test/chord-preserve.ly [new file with mode: 0644]
lily/chord-name-engraver.cc
lily/chord.cc [new file with mode: 0644]
lily/dynamic-engraver.cc
lily/include/chord-name-engraver.hh
lily/include/chord.hh [new file with mode: 0644]
lily/include/lily-proto.hh
lily/my-lily-parser.cc

index 686463e19f9078e81b830d70b863343776d5eb5e..543502d4a03b1c7114ac25d97518ac7d28aa5eea 100644 (file)
@@ -5,10 +5,15 @@ TestedFeatures =       "chord inversions";
 }
 
 inversions = \notes\transpose c''\chords{
+       % inversions ignored here
        c1 c-sus c-6 c/e c/g c/d
        % now try to find chords with inversions
        \property Score.chordInversion = 1 
-       c1 c-sus c-6 c/e c/g c/d
+       \property Score.chordInversionPreserve = 1 
+       c1 c-sus c-6 
+       c/e % c/e is not found because preserving doesn't work fully yet...
+       c/g
+       c/d % this triggers a warning: no 'd' in chord of c
 }
 
 \score{
diff --git a/input/test/chord-preserve.ly b/input/test/chord-preserve.ly
new file mode 100644 (file)
index 0000000..b7e3998
--- /dev/null
@@ -0,0 +1,27 @@
+koorden = \chords{ 
+       c1-2/d c-2.3/d 
+}
+
+
+\score{
+       <
+       \property Score.chordInversion = "1"
+               \type ChordNames {
+                       \property Score.chordInversionPreserve = "0"
+                       \koorden
+                       \property Score.chordInversionPreserve = "1"
+                       \koorden
+               }
+               \type Staff \notes\transpose c''{
+                       \property Score.chordInversionPreserve = "0"
+                       \koorden
+                       % preserving doesn't work for staff yet
+                       % see lily/chord.cc
+                       \property Score.chordInversionPreserve = "1"
+                       \koorden
+               }
+       >
+       \paper{
+               linewidth = -1.;
+       }
+}
index df90680dc4e703e3f8f6566b1ef0f6245313960d..336eacb3ed4a36437d5485c61e58bc948e86f7b8 100644 (file)
@@ -7,6 +7,7 @@
 */
 
 #include "chord-name-engraver.hh"
+#include "chord.hh"
 #include "musical-request.hh"
 #include "paper-def.hh"
 #include "lookup.hh"
@@ -39,72 +40,6 @@ Chord_name_engraver::do_try_music (Music* m)
   return false;
 }
 
-  /*
-    find tonic: after longest line of triads
-   */
-int
-Chord_name_engraver::find_tonic_i () const
-{
-  int tonic_i = 0;
-  int longest_i = 0;
-  for (int i = 0; i < pitch_arr_.size (); i++)
-    for (int j = 0; j < pitch_arr_.size (); j++)
-      {
-       int gap = pitch_arr_[(i + j + 1) % pitch_arr_.size ()].notename_i_
-         - pitch_arr_[(i + j) % pitch_arr_.size ()].notename_i_;
-       while (gap < 0)
-         gap += 7;
-       gap %= 7;
-       if (gap != 2)
-         {
-           if (j > longest_i)
-             {
-               longest_i = j;
-               tonic_i = i;
-             }
-           break;
-         }
-      }
-
-  int biggest_i = 0;
-  if (!longest_i)
-    for (int i = 0; i < pitch_arr_.size (); i++)
-      {
-       int gap = pitch_arr_[i].notename_i_
-         - pitch_arr_[(i - 1 + pitch_arr_.size ()) 
-         % pitch_arr_.size ()].notename_i_;
-       while (gap < 0)
-         gap += 7;
-       gap %= 7;
-       if (gap > biggest_i)
-         {
-           biggest_i = gap;
-           tonic_i = i;
-         }
-      }
-  return tonic_i;
-}
-
-Array<Musical_pitch>
-Chord_name_engraver::rebuild_pitch_arr (int tonic_i) const
-{
-  Musical_pitch last (0, 0, -5);
-  Array<Musical_pitch> pitches;
-  for (int i = 0; i < pitch_arr_.size (); i++)
-    {
-      Musical_pitch p = pitch_arr_[(tonic_i + i) % pitch_arr_.size ()];
-      if (p < last)
-       {
-         p.octave_i_ = last.octave_i_;
-         if (p < last)
-           p.octave_i_++;
-       }
-      pitches.push (p);
-      last = p;
-    }
-  return pitches;
-}
-
 void
 Chord_name_engraver::do_process_requests ()
 {
@@ -125,20 +60,26 @@ Chord_name_engraver::do_process_requests ()
 
    */
 
-  int tonic_i = 0;
-  Musical_pitch inversion = pitch_arr_[0];
-  Scalar chord_inversions = get_property ("chordInversion", 0);
-  if (chord_inversions.to_bool ())
+  Chord chord (pitch_arr_);
+  Musical_pitch* inversion = 0;
+  Scalar chord_inversion = get_property ("chordInversion", 0);
+  if (chord_inversion.to_bool ())
     {
-      tonic_i = find_tonic_i ();
+      int tonic_i = chord.find_tonic_i ();
       if (tonic_i)
-       pitch_arr_ = rebuild_pitch_arr (tonic_i);
+       {
+         inversion = &pitch_arr_[0];
+         Scalar preserve = get_property ("chordInversionPreserve", 0);
+         if (preserve.to_bool ())
+           chord.rebuild_from_base (tonic_i);
+         else
+           chord.rebuild_insert_inversion (tonic_i);
+       }
     }
     
-
   G_text_item* item_p =  new G_text_item;
 
-  item_p->text_str_ = banter_str (pitch_arr_, tonic_i, inversion);
+  item_p->text_str_ = chord.banter_str (inversion);
   
   Scalar style = get_property ("textstyle", 0);
   if (style.length_i ())
@@ -158,75 +99,3 @@ Chord_name_engraver::do_pre_move_processing ()
   text_p_arr_.clear ();
   pitch_arr_.clear ();
 }
-
-String
-Chord_name_engraver::banter_str (Array<Musical_pitch> pitch_arr, int tonic_i, Musical_pitch inversion) const
-{
-  Musical_pitch tonic = pitch_arr[0];
-
-  Array<Musical_pitch> scale;
-  scale.push (Musical_pitch (0)); // c
-  scale.push (Musical_pitch (1)); // d
-  scale.push (Musical_pitch (2)); // e
-  scale.push (Musical_pitch (3)); // f
-  scale.push (Musical_pitch (4)); // g
-  scale.push (Musical_pitch (5)); // a
-  // 7 always means 7-...
-  scale.push (Musical_pitch (6, -1)); // b
-
-
-  for (int i = 0; i < scale.size (); i++)
-    scale[i].transpose (tonic);
-
-  //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];
-
-  String add_str;
-  String sub_str;
-  String sep_str;
-  int last_trap = 1;
-  for (int i=1; i < pitch_arr.size (); i++)
-    {
-      Musical_pitch p = pitch_arr[i];
-      int trap = p.notename_i_ - tonic.notename_i_
-        + (p.octave_i_ - tonic.octave_i_) * 7 + 1;
-      while (trap - last_trap > 2)
-       {
-         last_trap += 2;
-         sub_str += sep_str + "no" + to_str (last_trap);
-         sep_str = "/";
-       }
-      last_trap = trap;
-      int accidental = p.accidental_i_ - scale[(trap - 1) % 7].accidental_i_;
-      if ((trap == 3) && (accidental == -1))
-        tonic_str += "m"; // hmm
-      else if (accidental || (!(trap % 2) || ((i + 1 == pitch_arr.size ()) && (trap > 5))))
-        {
-         add_str += sep_str;
-          if ((trap == 7) && (accidental == 1))
-            add_str += "maj7";
-          else
-            {
-              add_str += to_str (trap);
-              if (accidental)
-                add_str += accidental < 0 ? "-" : "+";
-            }
-         sep_str = "/";
-       }
-    }
-
-  String inversion_str;
-  if (tonic_i)
-    {
-      inversion_str = inversion.str ();
-      inversion_str = "/" + inversion_str.left_str (1).upper_str ()
-       + acc[tonic.accidental_i_ + 2];
-
-    }
-
-  String str = tonic_str + "$^{" + add_str + sub_str + "}$" + inversion_str;
-  return str;
-}
diff --git a/lily/chord.cc b/lily/chord.cc
new file mode 100644 (file)
index 0000000..26ae4ce
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+  chord.cc -- implement Chord
+
+  source file of the GNU LilyPond music typesetter
+
+  (c)  1999 Jan Nieuwenhuizen <janneke@gnu.org>
+*/
+
+#include "chord.hh"
+#include "warn.hh"
+
+Chord::Chord (Array<Musical_pitch> pitch_arr)
+{
+  pitch_arr_ = pitch_arr;
+}
+
+// construct from parser output
+// urg: should split this up into understandable chunks
+Chord::Chord (Musical_pitch tonic, Array<Musical_pitch>* add_arr_p, Array<Musical_pitch>* sub_arr_p, Musical_pitch* inversion_p)
+{
+  for (int i = 0; i < add_arr_p->size (); i++)
+    {
+      Musical_pitch p = tonic;
+      Musical_pitch q = (*add_arr_p)[i];
+      // duh, c7 should mean <c bes>
+      if (q.notename_i_ == 6)
+        q.accidental_i_--;
+      p.transpose (q);
+      (*add_arr_p)[i] = p;
+    }
+  add_arr_p->sort (Musical_pitch::compare);
+  for (int i = 0; i < sub_arr_p->size (); i++)
+    {
+      Musical_pitch p = tonic;
+      Musical_pitch q = (*sub_arr_p)[i];
+      // duh, c7 should mean <c bes>
+      if (q.notename_i_ == 6)
+        q.accidental_i_--;
+      p.transpose (q);
+      (*sub_arr_p)[i] = p;
+    }
+  sub_arr_p->sort (Musical_pitch::compare);
+
+  Musical_pitch third (2);
+  Musical_pitch mthird (2, -1);
+  Musical_pitch missing;
+  missing = tonic;
+  missing.transpose (third);
+
+  Musical_pitch p;
+  p = tonic;
+  p.transpose (third);
+  p.transpose (mthird);
+
+  /*
+   must have minimum at 5 (3 is added automatically as missing)
+   */
+  if (!add_arr_p->size ())
+    add_arr_p->push (p);
+  else if ((add_arr_p->top () < p) && (add_arr_p->top ().notename_i_ != p.notename_i_))
+    add_arr_p->push (p);
+  add_arr_p->sort (Musical_pitch::compare);
+
+  Array<Musical_pitch> triads;
+  triads.push (third);   // c e 
+  triads.push (mthird);  // d f 
+  triads.push (mthird);  // e g 
+  triads.push (third);   // f a 
+  triads.push (third);   // g b 
+  triads.push (mthird);  // a c 
+  triads.push (mthird);  // b d 
+
+  /*
+    if first addition is 4, assume sus4 and don't add third implicitely
+   */
+  Musical_pitch sus (3);
+  sus.transpose (tonic);
+  if (add_arr_p->size ())
+    if ((*add_arr_p)[0] == sus)
+      missing.transpose (mthird);
+
+  /*
+   add missing triads
+   */
+  for (int i = 0; i < add_arr_p->size ();)
+    {
+      Musical_pitch p = (*add_arr_p)[i];
+      if (p > missing)
+        while (p > missing)
+         {
+           if (p.notename_i_ != missing.notename_i_)
+             {
+               if ((missing.notename_i_ - tonic.notename_i_ + 7) % 7 == 6)
+                 {
+                   Musical_pitch special_seven = missing;
+                   Musical_pitch lower (0, -1);
+                   special_seven.transpose (lower);
+                   add_arr_p->insert (special_seven, i++);
+                 }
+               else
+                 add_arr_p->insert (missing, i++);
+             }
+           missing.transpose (triads[(missing.notename_i_ - tonic.notename_i_ + 7) % 7]);
+         }
+      else if (p.notename_i_ == missing.notename_i_)
+        missing.transpose (triads[(missing.notename_i_ - tonic.notename_i_ + 7) % 7]);
+      else
+       i++;
+    }
+
+  /*
+    add tonic
+   */
+  if (!add_arr_p->size () || ((*add_arr_p)[0] != tonic))
+    add_arr_p->insert (tonic, 0);
+
+  /*
+   add all that aren't subtracted
+   */
+  for (int i = 0; i < add_arr_p->size (); i++)
+    {
+      Musical_pitch p = (*add_arr_p)[i];
+      int j = 0;
+      for (; j < sub_arr_p->size (); j++)
+       if (p == (*sub_arr_p)[j])
+         {
+           sub_arr_p->del (j);
+           j = -1;
+           break;
+         }
+      if (j == sub_arr_p->size ())
+        pitch_arr_.push (p);
+    }
+
+  for (int i = 0; i < sub_arr_p->size (); i++)
+    warning (_f ("invalid subtraction: not part of chord: %s",
+                (*sub_arr_p)[i].str ()));
+
+  if (inversion_p)
+    {
+      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_))
+         break;
+      if (i == pitch_arr_.size ())
+       warning (_f ("invalid inversion pitch: not part of chord: %s",
+                     inversion_p->str ()));
+      else
+        {
+         /*
+           urg
+           should be run-time switchable "chordInversionPreserve", howto?
+
+           there are two ways commonly used to rearrange a chord with
+           an inversion:
+
+           1. rebuild pitch list, taking inversion as base
+             */
+#if 0
+         rebuild_from_base (i);
+#else
+         /*
+           or
+           2. insert inversion as lowest (at first position)
+         */
+         rebuild_with_bass (i);
+#endif
+       }
+      delete inversion_p;
+    }
+}
+
+String
+Chord::banter_str (Musical_pitch* inversion) const
+{
+  Musical_pitch tonic = pitch_arr_[0];
+
+  Array<Musical_pitch> scale;
+  scale.push (Musical_pitch (0)); // c
+  scale.push (Musical_pitch (1)); // d
+  scale.push (Musical_pitch (2)); // e
+  scale.push (Musical_pitch (3)); // f
+  scale.push (Musical_pitch (4)); // g
+  scale.push (Musical_pitch (5)); // a
+  // 7 always means 7-...
+  scale.push (Musical_pitch (6, -1)); // b
+
+
+  for (int i = 0; i < scale.size (); i++)
+    scale[i].transpose (tonic);
+
+  //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];
+
+  String add_str;
+  String sub_str;
+  String sep_str;
+  String sub_sep_str;
+  int last_trap = 1;
+  for (int i=1; i < pitch_arr_.size (); i++)
+    {
+      Musical_pitch p = pitch_arr_[i];
+      int trap = p.notename_i_ - tonic.notename_i_
+        + (p.octave_i_ - tonic.octave_i_) * 7;
+      while (trap < 0)
+        trap += 7;
+      trap++;
+      while (trap - last_trap > 2)
+       {
+         last_trap += 2;
+         sub_str += sub_sep_str + "no" + to_str (last_trap);
+         sub_sep_str = "/";
+       }
+      last_trap = trap;
+      int accidental = p.accidental_i_ - scale[(trap - 1) % 7].accidental_i_;
+      if ((trap == 3) && (accidental == -1))
+        tonic_str += "m"; // hmm
+      else if (accidental || (!(trap % 2) || ((i + 1 == pitch_arr_.size ()) && (trap > 5))))
+        {
+         add_str += sep_str;
+          if ((trap == 7) && (accidental == 1))
+            add_str += "maj7";
+          else
+            {
+              add_str += to_str (trap);
+              if (accidental)
+                add_str += accidental < 0 ? "-" : "+";
+             // catch "C4/no3"; remove "no3"
+             if (trap == 4)
+               {
+                 int i = sub_str.index_i ("no3");
+                 if (i != -1)
+                   sub_str = sub_str.nomid_str (i, 3);
+                 if (!sub_str.length_i ())
+                   sub_sep_str = "";
+               }
+            }
+         sep_str = "/";
+       }
+    }
+
+  String inversion_str;
+  if (inversion)
+    {
+      inversion_str = inversion->str ();
+      inversion_str = "/" + inversion_str.left_str (1).upper_str ()
+       + acc[tonic.accidental_i_ + 2];
+
+    }
+
+  if (sub_str.length_i ())
+    sub_str = sep_str + sub_str;
+  String str = tonic_str + "$^{" + add_str + sub_str + "}$" + inversion_str;
+  return str;
+}
+
+int
+Chord::find_tonic_i () const
+{
+  /*
+    find tonic
+    
+    first try: base of longest line of triads
+   */
+  int tonic_i = 0;
+  int longest_i = 0;
+  for (int i = 0; i < pitch_arr_.size (); i++)
+    {
+      int no_triad_i = 0;
+      int last_i = pitch_arr_[i % pitch_arr_.size ()].notename_i_;
+      int j = 0;
+      for (; j < pitch_arr_.size (); j++)
+       {
+         int cur_i = pitch_arr_[(i + j + 1) % pitch_arr_.size ()].notename_i_;
+         int gap = cur_i - last_i;
+         while (gap < 0)
+           gap += 7;
+         gap %= 7;
+         if (gap == 2)
+           last_i = cur_i;
+         else
+           no_triad_i++;
+       }
+      if (j - no_triad_i > longest_i)
+       {
+         longest_i = j - no_triad_i;
+         tonic_i = i;
+       }
+    }
+
+  /*
+    second try: note after biggest gap
+   */
+  int biggest_i = 0;
+  //  if (longest_i)
+  if (longest_i <= 1)
+    for (int i = 0; i < pitch_arr_.size (); i++)
+      {
+       int gap = pitch_arr_[i].notename_i_
+         - pitch_arr_[(i - 1 + pitch_arr_.size ()) 
+         % pitch_arr_.size ()].notename_i_;
+       while (gap < 0)
+         gap += 7;
+       gap %= 7;
+       if (gap > biggest_i)
+         {
+           biggest_i = gap;
+           tonic_i = i;
+         }
+      }
+  return tonic_i;
+}
+
+void
+Chord::rebuild_from_base (int base_i)
+{
+  Musical_pitch last (0, 0, -5);
+  Array<Musical_pitch> new_arr;
+  for (int i = 0; i < pitch_arr_.size (); i++)
+    {
+      Musical_pitch p = pitch_arr_[(base_i + i) % pitch_arr_.size ()];
+      if (p < last)
+       {
+         p.octave_i_ = last.octave_i_;
+         if (p < last)
+           p.octave_i_++;
+       }
+      new_arr.push (p);
+      last = p;
+    }
+  pitch_arr_ = new_arr;
+}
+
+void
+Chord::rebuild_insert_inversion (int tonic_i)
+{
+  Musical_pitch inversion = pitch_arr_.get (0);
+  rebuild_from_base (tonic_i - 1);
+  if (pitch_arr_.size ())
+    {
+      inversion.octave_i_ = pitch_arr_[0].octave_i_ - 1;
+      while (inversion < pitch_arr_[0])
+       inversion.octave_i_++;
+    }
+  for (int i = 0; i < pitch_arr_.size (); i++)
+    if (pitch_arr_[i] > inversion)
+      {
+       pitch_arr_.insert (inversion, i);
+       break;
+      }
+}
+
+void
+Chord::rebuild_with_bass (int bass_i)
+{
+  Musical_pitch inversion = pitch_arr_.get (bass_i);
+  // is lowering fine, or should others be raised?
+  if (pitch_arr_.size ())
+    while (inversion > pitch_arr_[0])
+      inversion.octave_i_--;
+  pitch_arr_.insert (inversion, 0);
+}
index 2a28d1541015979918d777f3fc09f78bca66e96b..d36eeb250a5e16e6520cc8fba33c92120bcd170e 100644 (file)
@@ -102,6 +102,7 @@ Dynamic_engraver::do_process_requests()
 
          staff_side_p_ = new G_staff_side_item;
          staff_side_p_->set_victim (text_p_);
+         staff_side_p_->axis_ = Y_AXIS;
          
 
          prop = get_property ("dynamicDir", 0);
@@ -173,8 +174,10 @@ Dynamic_engraver::do_pre_move_processing()
   if (to_end_cresc_p_)
     to_end_cresc_p_->add_support (s_l);
   if (staff_side_p_)
-    staff_side_p_->add_support (s_l);
-
+    {
+      staff_side_p_->add_support (s_l);
+      //      staff_side_p_->dim_cache_[Y_AXIS].parent_l_ =  &s_l->dim_cache_[Y_AXIS];
+    }
 
   typeset_all ();
 }
index 72b221fe1ea7dc97773350df1d536ff471ba2ea9..233714f017ce578569067613a359a7759555fdfe 100644 (file)
 
 #include "lily-proto.hh"
 
+Array<Musical_pitch> rebuild_from_base_pitch_arr (Array<Musical_pitch> pitch_arr, int base_i);
+Array<Musical_pitch> rebuild_insert_inversion_pitch_arr (Array<Musical_pitch> pitch_arr, int tonic_i);
+Array<Musical_pitch> rebuild_with_bass_pitch_arr (Array<Musical_pitch> pitch_arr, int bass_i);
+
+
 class Chord_name_engraver : public Engraver 
 {
 protected:
@@ -31,7 +36,7 @@ private:
   Array<Musical_pitch> pitch_arr_;
   Link_array<Item> text_p_arr_;
 
-  String banter_str (Array<Musical_pitch> pitch_arr, int tonic_i, Musical_pitch inversion) const;
+  String banter_str (Array<Musical_pitch> pitch_arr, Musical_pitch* inversion) const;
   int find_tonic_i () const;
   Array<Musical_pitch> rebuild_pitch_arr (int tonic_i) const;
 };
diff --git a/lily/include/chord.hh b/lily/include/chord.hh
new file mode 100644 (file)
index 0000000..0fc7601
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+  chord.hh -- declare Chord
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 1999 Jan Nieuwenhuizen <janneke@gnu.org>
+*/
+
+#ifndef CHORD_HH
+#define CHORD_HH
+
+#include "array.hh"
+#include "musical-pitch.hh"
+#include "lily-proto.hh"
+
+class Chord
+{
+public:
+  Chord (Array<Musical_pitch> pitch_arr);
+  Chord (Musical_pitch tonic, Array<Musical_pitch>* add_arr_p, Array<Musical_pitch>* sub_arr_p, Musical_pitch* inversion_p);
+
+  void rebuild_from_base (int base_i);
+  void rebuild_insert_inversion (int tonic_i);
+  void rebuild_with_bass (int bass_i);
+
+  String banter_str (Musical_pitch* inversion) const;
+  int find_tonic_i () const;
+
+  Array<Musical_pitch> pitch_arr_;
+  int tonic_i_;
+};
+
+#endif // CHORD_HH
index fb46f112a22b53232c221a7164688d9ee2a5dd66..0c600002f8c8258a2c2dcfb94a9227afbb6d6498 100644 (file)
@@ -50,6 +50,7 @@ struct Break_req;
 struct Cadenza_req;
 struct Change_iterator;
 struct Change_translator;
+struct Chord;
 struct Chord_name_engraver;
 struct Clef_change_req;
 struct Clef_item;
index d29b14ff5f6d68d01c01103946c10ffd884def24..8cbd830662d8e3b9939d5d73f264b55f505ddb62 100644 (file)
@@ -20,6 +20,7 @@
 #include "midi-def.hh"
 #include "paper-def.hh"
 #include "identifier.hh"
+#include "chord.hh"
 
 My_lily_parser::My_lily_parser (Sources * source_l)
 {
@@ -151,159 +152,11 @@ My_lily_parser::get_chord (Musical_pitch tonic, Array<Musical_pitch>* add_arr_p,
   Simultaneous_music*v = new Request_chord;
   v->set_spot (here_input ());
 
-  for (int i = 0; i < add_arr_p->size (); i++)
-    {
-      Musical_pitch p = tonic;
-      Musical_pitch q = (*add_arr_p)[i];
-      // duh, c7 should mean <c bes>
-      if (q.notename_i_ == 6)
-        q.accidental_i_--;
-      p.transpose (q);
-      (*add_arr_p)[i] = p;
-    }
-  add_arr_p->sort (Musical_pitch::compare);
-  for (int i = 0; i < sub_arr_p->size (); i++)
-    {
-      Musical_pitch p = tonic;
-      Musical_pitch q = (*sub_arr_p)[i];
-      // duh, c7 should mean <c bes>
-      if (q.notename_i_ == 6)
-        q.accidental_i_--;
-      p.transpose (q);
-      (*sub_arr_p)[i] = p;
-    }
-  sub_arr_p->sort (Musical_pitch::compare);
-
-  Musical_pitch third (2);
-  Musical_pitch mthird (2, -1);
-  Musical_pitch missing;
-  missing = tonic;
-  missing.transpose (third);
-
-  Musical_pitch p;
-  p = tonic;
-  p.transpose (third);
-  p.transpose (mthird);
-
-  /*
-   must have minimum at 5 (3 is added automatically as missing)
-   */
-  if (!add_arr_p->size ())
-    add_arr_p->push (p);
-  else if ((add_arr_p->top () < p) && (add_arr_p->top ().notename_i_ != p.notename_i_))
-    add_arr_p->push (p);
-  add_arr_p->sort (Musical_pitch::compare);
-
-  Array<Musical_pitch> triads;
-  triads.push (third);   // c e 
-  triads.push (mthird);  // d f 
-  triads.push (mthird);  // e g 
-  triads.push (third);   // f a 
-  triads.push (third);   // g b 
-  triads.push (mthird);  // a c 
-  triads.push (mthird);  // b d 
-
-  /*
-    if first addition is 4, assume sus4 and don't add third implicitely
-   */
-  Musical_pitch sus (3);
-  sus.transpose (tonic);
-  if (add_arr_p->size ())
-    if ((*add_arr_p)[0] == sus)
-      missing.transpose (mthird);
-
-  /*
-   add missing triads
-   */
-  for (int i = 0; i < add_arr_p->size (); i++)
-    {
-      Musical_pitch p = (*add_arr_p)[i];
-      if (p > missing)
-        while (p > missing)
-         {
-           if (p.notename_i_ != missing.notename_i_)
-             {
-               if ((missing.notename_i_ - tonic.notename_i_ + 7) % 7 == 6)
-                 {
-                   Musical_pitch special_seven = missing;
-                   Musical_pitch lower (0, -1);
-                   special_seven.transpose (lower);
-                   add_arr_p->insert (special_seven, i++);
-                 }
-               else
-                 add_arr_p->insert (missing, i++);
-             }
-           missing.transpose (triads[(missing.notename_i_ - tonic.notename_i_ + 7) % 7]);
-         }
-      else if (p.notename_i_ == missing.notename_i_)
-        missing.transpose (triads[(missing.notename_i_ - tonic.notename_i_ + 7) % 7]);
-      else
-       i++;
-    }
-
-  /*
-    add tonic
-   */
-  if (!add_arr_p->size () || ((*add_arr_p)[0] != tonic))
-    add_arr_p->insert (tonic, 0);
-
-  Array<Musical_pitch> pitch_arr;
-  /*
-   add all that aren't subtracted
-   */
-  for (int i = 0; i < add_arr_p->size (); i++)
-    {
-      Musical_pitch p = (*add_arr_p)[i];
-      int j = 0;
-      for (; j < sub_arr_p->size (); j++)
-       if (p == (*sub_arr_p)[j])
-         {
-           sub_arr_p->del (j);
-           j = -1;
-           break;
-         }
-      if (j == sub_arr_p->size ())
-        pitch_arr.push (p);
-    }
-
-  for (int i = 0; i < sub_arr_p->size (); i++)
-    warning (_f ("invalid subtraction: not part of chord: %s",
-                (*sub_arr_p)[i].str ()));
-
-  if (inversion_p)
-    {
-      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_))
-         break;
-      if (i == pitch_arr.size ())
-       warning (_f ("invalid inversion pitch: not part of chord: %s",
-                     inversion_p->str ()));
-      else
-        {
-         Array<Musical_pitch> pitches;
-         Musical_pitch last (0, 0, -5);
-         for (int j = 0; j < pitch_arr.size (); j++)
-           {
-             Musical_pitch p = pitch_arr[(j + i) % pitch_arr.size ()];
-             if (p < last)
-               {
-                 p.octave_i_ = last.octave_i_;
-                 if (p < last)
-                   p.octave_i_++;
-               }
-             pitches.push (p);
-             last = p;
-           }
-         pitch_arr = pitches;
-       }
-      delete inversion_p;
-    }
+  Chord chord (tonic, add_arr_p, sub_arr_p, inversion_p);
 
-  for (int i = 0; i < pitch_arr.size (); i++)
+  for (int i = 0; i < chord.pitch_arr_.size (); i++)
     {
-      Musical_pitch p = pitch_arr[i];
+      Musical_pitch p = chord.pitch_arr_[i];
       Note_req* n = new Note_req;
       n->pitch_ = p;
       n->duration_ = d;