gnu-music-discuss
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

got jazz chord plugin for use in last stable vers. 1.2.17 - anybody inte


From: Amelie Zapf
Subject: got jazz chord plugin for use in last stable vers. 1.2.17 - anybody interested?
Date: Tue, 6 Mar 2001 12:23:23 +0100

Hi folks,

I've written a jazz chord plugin yesterday for use in the stable 1.2.17 release
of lily. Works fine on my system, the code is a bit bloated, still. If anybody
is interested, see below. That code replaces the chord.cc file in the /lily
directory. I'd be glad if anybody could revise it (it's for an outdated
version, I know...).

Best wishes, Amy

/*
  chord.cc -- implement Chord

  source file of the GNU LilyPond music typesetter

  (c)  1999 Jan Nieuwenhuizen <address@hidden>

Jazz chord additions by Amelie Zapf 2001
  (c)  2001 Amelie Zapf (address@hidden)
*/

/*
  FIXME:

  A triad is a chord of three tones, and not an interval of a third.
 */

#include "chord.hh"
#include "warn.hh"

// doesn't seem common, and we should know about this during parsing
// #define INVERSION_ADDED_AS_BASE 1

Chord::Chord (Array<Musical_pitch> pitch_arr)
{
  pitch_arr_ = pitch_arr;
}

static void
rebuild_transpose (Musical_pitch tonic, Array<Musical_pitch>* pitch_arr_p)
{
  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);
      (*pitch_arr_p)[i] = p;
    }
  pitch_arr_p->sort (Musical_pitch::compare);
}

static int
find_pitch_i (Array<Musical_pitch> const* pitch_arr_p, Musical_pitch p)
{
  for (int i = 0; i < pitch_arr_p->size (); i++)
    if (p == (*pitch_arr_p)[i])
      return i;
  return -1;
}

static int
find_notename_i (Array<Musical_pitch> const* pitch_arr_p, Musical_pitch p)
{
  int i = find_pitch_i (pitch_arr_p, p);
  if (i == -1)
    {
      for (int i = 0; i < pitch_arr_p->size (); i++)
        {
          p.octave_i_ = (*pitch_arr_p)[i].octave_i_;
          if (p == (*pitch_arr_p)[i])
            return i;
        }
    }
  return i;
}

/*
  trap (NL) != trap(english)
 */
static int
trap_i (Musical_pitch tonic, Musical_pitch p)
{
  int i = p.notename_i_ - tonic.notename_i_
    + (p.octave_i_ - tonic.octave_i_) * 7;
  while (i < 0)
    i += 7;
  i++;
  return i;
}

static Array<Musical_pitch>
missing_triads_pitch_arr (Array<Musical_pitch>const* pitch_arr_p)
{
  Array<Musical_pitch> triads;

  /* is the third c-e, d-f, etc. small or large? */
  int minormajor_a[] = {0, -1, -1, 0,0,-1,-1};
  for (int i=0; i < 7; i++)
    triads.push (Musical_pitch( 2, minormajor_a[i]));

  Musical_pitch tonic = (*pitch_arr_p)[0];
  Musical_pitch last = tonic;
  Array<Musical_pitch> missing_arr;

  for (int i = 0; i < pitch_arr_p->size ();)
    {
      Musical_pitch p = (*pitch_arr_p)[i];
      int trap = trap_i (tonic, p);
      if (last.notename_i_ == p.notename_i_)
        last.transpose (triads[(last.notename_i_ - tonic.notename_i_ + 7) % 7]);
      if (trap > trap_i (tonic, last))
        {
          while (trap > trap_i (tonic, last))
            {
              if ((last.notename_i_ - tonic.notename_i_ + 7) % 7 == 6)
                {
                  Musical_pitch special_seven = last;
                  Musical_pitch lower (0, -1);
                  special_seven.transpose (lower);
                  missing_arr.push (special_seven);
                }
              else
                {
                  missing_arr.push (last);
                }
              last.transpose (triads[(last.notename_i_ - tonic.notename_i_ + 7) 
% 7]);
            }
        }
      else
        {
          i++;
        }
    }
  return missing_arr;
}


/*
  construct from parser output
*/
Chord::Chord (Musical_pitch tonic, Array<Musical_pitch>* add_arr_p, 
Array<Musical_pitch>* sub_arr_p, Musical_pitch* inversion_p)
{
  rebuild_transpose (tonic, add_arr_p);
  rebuild_transpose (tonic, sub_arr_p);

  Musical_pitch fifth = tonic;
  fifth.transpose (Musical_pitch (2));
  fifth.transpose (Musical_pitch (2, -1));

  /*
    remove double adds (urg: sus4)
   */
  for (int i = add_arr_p->size () - 1; i >= 0 ; i--)
    {
      int j = ::find_pitch_i (add_arr_p, (*add_arr_p)[i]);
      if ((j != -1) && (i != j))
        {
            add_arr_p->get (i);
        } 
    }

  /*
    default chord includes upto 5: <1, 3, 5>
   */
  add_arr_p->insert (tonic, 0);
  Array<Musical_pitch> tmp = *add_arr_p;
  int highest_trap = trap_i (tonic, tmp.top ());
  if (highest_trap < 5)
    tmp.push (fifth);

  /*
    find missing triads
   */
  Array<Musical_pitch> missing_arr = missing_triads_pitch_arr (&tmp);
  if (highest_trap < 5)
    missing_arr.push (fifth);

  /*
    if additions include some 3, don't add third
   */
  Musical_pitch third = tonic;
  third.transpose (Musical_pitch (2));
  if (::find_notename_i (add_arr_p, third) != -1)
    {
      int i = ::find_pitch_i (&missing_arr, third);
      if (i != -1)
        missing_arr.get (i);
    }
  
  /*
    if additions include 4, assume sus4 and don't add third implicitely
     C-sus (4) = c f g (1 4 5)
   */
  Musical_pitch sus = tonic;
  sus.transpose (Musical_pitch (3));
  if (::find_pitch_i (add_arr_p, sus) != -1)
    {
      int i = ::find_pitch_i (&missing_arr, third);
      if (i != -1)
        missing_arr.get (i);
    }

  /*
    if additions include some 5, don't add fifth
   */
  if (::find_notename_i (add_arr_p, fifth) != -1)
    {
      int i = ::find_pitch_i (&missing_arr, fifth);
      if (i != -1)
        missing_arr.get (i);
    }
  
  
  /*
    complete the list of triads to be added
   */
  add_arr_p->concat (missing_arr);
  add_arr_p->sort (Musical_pitch::compare);

  /*
   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);
    }

  pitch_arr_.sort (Musical_pitch::compare);

  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
        {
#if INVERSION_ADDED_AS_BASE
          pitch_arr_.insert (pitch_arr_[i], 0);
          rebuild_with_bass (0);
#else
          rebuild_with_bass (i);
#endif
          
        }
      delete inversion_p;
    }
}

void
Chord::find_additions_and_subtractions(Array<Musical_pitch>* add_arr_p, 
Array<Musical_pitch>* sub_arr_p) const
{
  Musical_pitch tonic = pitch_arr_[0];
  /*
    construct an array of triads for a normal chord
   */
  Array<Musical_pitch> all_arr;
  all_arr.push (tonic);
  all_arr.push (pitch_arr_.top ());
  all_arr.concat (missing_triads_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 a = all_arr [i <? all_arr.size () - 1];
      Musical_pitch p = pitch_arr_ [j <? pitch_arr_.size () - 1];
      /*
        this pitch is present: do nothing, check next
       */
      if (a == p)
        {
          i++;
          j++;
        }
      /*
        found an extra pitch: chord addition
       */
      else if ((p < a) || (p.notename_i_ == a.notename_i_))
        {
          add_arr_p->push (p);
          (j < pitch_arr_.size ()) ? j++ : i++;
        }
      /*
        a triad is missing: chord subtraction
       */
      else
        {
          sub_arr_p->push (a);
          (i < all_arr.size ()) ? i++ : j++;
        }
    }
      
  /*
    add highest addition, because it names chord
    (1, 3 and) 5 not an addition: part of normal chord
   */
  if (trap_i (tonic, pitch_arr_.top () > 5))
    add_arr_p->push (pitch_arr_.top ());
}

String
Chord::banter_str (Musical_pitch* inversion) 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 (tonic, &scale);
  
  bool has3m_b = false;
  bool has4_b = false;

  /*---initializing a couple more for higher intervals---*/
  bool hasmaj7_b = false;
  bool hasflat5_b = false;
  bool hassharp5_b = false;
  bool hasalt9_b = false;
  bool hasalt11_b = false;
  bool addition_typeset_b = false;
  bool alt7_typeset_b = false;
  bool add_contained_b = false;
  String no3_str;
  String no5_str;
  String no7_str;
  String no9_str;
  String no11_str;
  /*---End of addition---*/

  String str;
  String sep_str;

  for (int i = 0; i < sub_arr.size (); i++)
    {
      Musical_pitch p = sub_arr[i];
      int trap = trap_i (tonic, p);
      if (trap == 3) no3_str = "no 3";
      if (trap == 5) no5_str = "no 5";
      if (trap == 7) {
        no7_str = "add";
        add_contained_b = true;
      }
      if (trap == 9) {
        no9_str = "add";
        no7_str = "";
        add_contained_b = true;
      }
      if (trap == 11) {
        no11_str = "add";
        no9_str = "";
        add_contained_b = true;
      }
    }


  for (int i = 0; i < add_arr.size (); i++)
    {
      Musical_pitch p = add_arr[i];
      int trap = trap_i (tonic, p);
      addition_typeset_b = false;
      if (trap == 4)
        has4_b = true;
        
      /*---Declaration of the accidental---*/
      int accidental = p.accidental_i_ - scale[(trap - 1) % 7].accidental_i_;

      /*---Determine if chord is minor---*/
      if ((trap == 3) && (accidental == -1))
        {
          tonic_str += "m";
          has3m_b = true;
        }
        
      /*---Do the following if:
                -accidental present or                                  
PERFECTLY FINE
                -trap (step) uneven or                                  
PERFECTLY FINE (except for 6/9 chords and the like)
                -chord addition highest and higher than the fifth       
DISGUSTING
           PROJECT:     have to think about this, I'm not yet very clear ---*/

      else if (accidental
               || (!(trap % 2) || ((i + 1 == add_arr.size ()) && (trap > 5))))
        {
          str += sep_str;
          if ((trap == 7) && (accidental == 1)) {
            str += "maj7";

            /*---Beginning of addition ---*/
            hasmaj7_b = true;
            addition_typeset_b = true;
            /*---End of addition---*/
          }     
          else
            {

              /*---this is exceptionally disgusting, let it be changed
              str += to_str (trap);
              if (accidental)
                str += accidental < 0 ? "-" : "+";
              End of disgusting part---*/

              /*---Beginning of addition---*/
              if ((trap != 4) && (trap != 5)) {
                if ((trap == 9) && (!(hasmaj7_b))) str += no7_str;
                if (trap == 11) {
                  if (!(hasmaj7_b)) str += no7_str;
                  str += no9_str;
                }
                if (trap == 13) {
                  if (!(hasmaj7_b)) str += no7_str;
                  str += no9_str;
                  str += no11_str;
                }
                if ((!(add_contained_b)) && (accidental && 
(!(alt7_typeset_b)))) {
                  str += "7/";
                  alt7_typeset_b = true;
                }
                if (accidental) str += accidental < 0 ? "\\textflat" : 
"\\textsharp";
                str += to_str (trap);
                addition_typeset_b = true;
              }
              if ((trap == 5) && (accidental < 0)) hasflat5_b=true;
              if ((trap == 5) && (accidental > 0)) hassharp5_b=true;
              if ((trap == 9) && (accidental)) hasalt9_b=true;
              if ((trap == 11) && (accidental)) hasalt11_b=true;
              /*---End of addition---*/
            }
          if (addition_typeset_b) {sep_str = "/";} else {sep_str = "";}
        }
    }
  if ((((hasflat5_b) || (hassharp5_b)) || (has4_b)) && (addition_typeset_b)) 
str += "/";
  if (hasflat5_b && addition_typeset_b) str += "\\textflat";
  if (hassharp5_b && addition_typeset_b) str += "\\textsharp";
  if (hasflat5_b && (!(addition_typeset_b))) str += "-";
  if (hassharp5_b && (!(addition_typeset_b))) str += "+";
  if ((hasflat5_b) || (hassharp5_b)) str += "5";
  if (((hasflat5_b) || (hassharp5_b)) && (has4_b)) str += "/";
  if (has4_b) str += "sus 4";   


  if ((no3_str != "") && (!(has3m_b || has4_b))) {
    str += sep_str;
    str += no3_str;
    sep_str = "/";
  }
  if ((no5_str != "") && (!(hasflat5_b || hassharp5_b))) {
    str += sep_str;
    str += no5_str;
  }


  String inversion_str;
  if (inversion)
    {
      inversion_str = inversion->str ();
      inversion_str = "/" + inversion_str.left_str (1).upper_str ()
        + acc[inversion->accidental_i_ + 2];

    }

  return tonic_str + "$^{" + str + "}$" + inversion_str;
}

int
Chord::find_notename_i (Musical_pitch p) const
{
  return ::find_notename_i (&pitch_arr_, p);
}

int
Chord::find_pitch_i (Musical_pitch p) const
{
  return ::find_pitch_i (&pitch_arr_, p);
}

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)
{
  assert (base_i >= 0);
  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)
{
  assert (tonic_i > 0);
#if INVERSION_ADDED_AS_BASE
  // inversion was added; don't insert
  Musical_pitch inversion = pitch_arr_.get (0);
  (void)inversion;
#else
  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;
      }
#endif
}

void
Chord::rebuild_with_bass (int bass_i)
{
  assert (bass_i >= 0);
  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);
}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]