[Top][All Lists]
[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);
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- got jazz chord plugin for use in last stable vers. 1.2.17 - anybody interested?,
Amelie Zapf <=