-i-*-outline-layout:(2 (-1 -1 0 :) 0);outline-stylish-prefixes:nil -*-
+-*-outline-layout:(2 (-1 -1 0 :) 0);outline-stylish-prefixes:nil -*-
* GNU LilyPond TODO
Features you cannot find in the documentation as working, should be
.* TODO
. * make this file understandable for 3rd parties.
-. * use Rhythmic_head::position_i () for all Staff_referenced
+. * break align order from SCM list.
+. * time description should be put into SCM
+. * context in embedded SCM errors.
+
. * eradicate all VIRTUAL_COPY_CONS () macros ; use indexed creation,
eg.
ctor_dict["Score_element"]->create_func ();
. * acc at tied note after linebreak.
+. * fix font-naming and selecting
+. * fix naming: \interline Context.staffLineLeading, staff_line_leading (),
+staff_position staff_space
+. * chord tonic: placement of accidental C#, Cb (from scm and C++)
. * note head on stem err msg in dutch.
-. * why need to run -C mf twice?
+. * why need to run -C mf twice?
. * setting indent to 0 with \shape fails
. * here's no difference at all in output. When either is jacked up to 7.0,
everything works and matches up; when either is set just a bit above the
. * hara kiri _8 clef.
. * junk -M ?
. * mudela-book doco
-. * rerun profile
. * fix or replace feta-accordion.mf
. * script engraver
. * bracket pdf hack
- for one of my test scores containing a modern edition of an early
17'th century composition I have a leading measure containing the
orginal clefs and note values of the original composition. I use the
-"harmonic" and "diamond" note head styles for that measure and would
+a"harmonic" and "diamond" note head styles for that measure and would
like to have the stems of these notes _centered_ on the notehead as in
the mensural music notation.
bar line fully drawn across the staves and after that keep to the
ChoirStaff bar line types in the rest of the scores
-- autoBeamMelisma: if I explicitly beam notes in a staff with auto
-beaming disabled I would like to have these beams also to be
-melismatic.
-
. * make all Feta (including dynamics) available to the user in
textual scripts. Examples: "D.S. al \coda", "\mf espress.".
-. * Write scritp that uses --find-old-relative to do auto relativization.
+. * Write script that uses --find-old-relative to do auto relativization.
. * Junk shared cruft (duration, moment) in lib/
. * Key_engraver, Local_key_item
. * Think of comprehensive solution for "if (grace_b == self_grace_b_)"
. * String[String.length] doesn't trap.
-. * Beam
-. * Stem
. * Rhythmic_column and interaction stem/rhythmic_column/note_head/dots.
. * Duration
. * clef engraver
. * junk Music_iterator::first_b_
. * Bezier
-.* BUGS
-. * [c8. c16 c16 c16] in 6/8 timesig.
+.* Beams
+. * [c8. c16 c16 c16] in 6/8 timesig.
+. * Rewrite Stem, Beam (hairy)
+. * general shaving on Beam and Stem
+. * use plet grouping
+. * beams over bars
+. * Rests and beams don't work too well together. Example:
+ [ r8 g''16 des'] [r8 c16 a]
+. * autoBeamMelisma: if I explicitly beam notes in a staff with auto
+beaming disabled I would like to have these beams also to be
+melismatic.
+. * The stemLength property should affect also beamed stems.
. * staffside spanner (crescendo!) along with staffswitch.
+. * * auto melismaBusy for beams.
. *
> \context Staff <
.* STUFF
. * We need feta-din*.mf files for more sizes than 10.
-- Rests and beams don't work too well together. Example:
- [ r8 g''16 des'] [r8 c16 a]
-
-- The stemLength property should affect also beamed stems.
-
. * align left edge of broken tuplet-spanner (have a test case?)
. * fix dynamics decently, ie. use kerning & ligatures.
. * key restorations & repeats
. * paperXX.ly \quartwidth, font setting not up to date. (Should read from AFM?)
-. * * auto melismaBusy for beams.
. *In Caro Mio Ben, bar 8, there's a syllable that starts on a note, and
ends on a pair of grace notes. Standard practice is to mark this with
a slur starting on the main note and ending on the grace note, so a
. * do --safe for PS output?
. * msgfmt -o check?
. * collision of lyrics with span_bars. See star-spangled.
-. * Auto_beam debugging output (waarom/wanneer heb jij die weggehaald?)
. * It is impossible to typeset two textual scripts that are stacked
on top of eachother and avoids note collisions and at the same
time are typeset with different textStyle. I tried to move around
. * german
. * dutch
. * swedish
- .. ?
. * chords
. * guitar chords (fret diagrams)
. * input converters
. * NIFF?
-. * ABC?
-. * SMDL?
+. * musedata
. * add to MIDI output:
. * sharp / flat on trills (in MIDI ??)
. * account for rhythmic position in measure
. * etc.
-
. * Output class, handles : (smallish)
. * help text /(c) notice?
. * version line
. * PS lines to .eps files
. * write custom prolog
-. * SGML input
-
-. * Documentation
-. * internal documentation
-
. * more spanners (smallish)
. * Glissando
. * trill
-. * Rewrite Stem, Beam (hairy)
-. * general shaving on Beam and Stem
-. * use plet grouping
-. * beams over bars
-
-. * lines:
-. * Ledger lines, should be separate item: Ledger_lines
-. * beam stem showthrough, inter beam sizes (french vs german style)
-
. * Collisions
. * left/right note balls should be handled by Collision:
< \multi 2; { \stem 1; <b c> } { <f as b> } >
. * input property
. * Figure out semicolons.
. * <c f a>4 ?
-. * Viola mode?
-
- @c c g e g
- for
- c g es g,
-
- @A c g e g
- for
- cis gis e gis
. * configure pitch_byte
. * rest name configurable
. * write Dynamic_line (to group dynamics horizontally)
-. * use Real for all y positions.
-
. * half-sharps, half-flats
. * adaptive accidental spacing.
#include "chord.hh"
#include "musical-request.hh"
#include "warn.hh"
+#include "debug.hh"
+#include "molecule.hh"
+#include "paper-def.hh"
+#include "lookup.hh"
+SCM
+pitch2scm (Musical_pitch p)
+{
+ return gh_cons (gh_int2scm (p.notename_i_), gh_int2scm (p.accidental_i_));
+}
/*
construct from parser output
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++)
{
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)
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);
}
Chord::Chord (Chord const& chord)
+ : Item (chord)
{
pitch_arr_ = chord.pitch_arr_;
inversion_p_ = chord.inversion_p_ ? new Musical_pitch (*chord.inversion_p_) : 0;
{
delete inversion_p_;
delete bass_p_;
+ // AAARGH, why doesn't Score_elt do this?
+ unsmobify_self ();
+}
+
+Array<Musical_pitch>
+Chord::base_arr (Musical_pitch 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);
}
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) const
{
- 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
*/
{
i++;
j++;
+ last_extra = tonic;
}
/*
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++;
+ 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"
+ word is roman text or styled text:
+ "text"
+ ("style" . "text")
*/
-String
-Chord::banter_str () const
+Molecule
+Chord::ly_word2molecule (SCM scm) const
{
- Musical_pitch tonic = pitch_arr_[0];
+ String style;
+ if (gh_pair_p (scm))
+ {
+ style = ly_scm2string (gh_car (scm));
+ scm = gh_cdr (scm);
+ }
+ String text = ly_scm2string (scm);
+ return lookup_l ()->text (style, text, paper_l ());
+}
+
+/*
+ scm is word or list of words:
+ word
+ (word word)
+ */
+Molecule
+Chord::ly_text2molecule (SCM scm) const
+{
+ Molecule mol;
+ if (gh_list_p (scm))
+ {
+ while (gh_cdr (scm) != SCM_EOL)
+ {
+ mol.add_at_edge (X_AXIS, RIGHT,
+ ly_word2molecule (gh_car (scm)), 0);
+ scm = gh_cdr (scm);
+ }
+ scm = gh_car (scm);
+ }
+ mol.add_at_edge (X_AXIS, RIGHT,
+ ly_word2molecule (scm), 0);
+ return mol;
+}
+
+Molecule
+Chord::pitch2molecule (Musical_pitch p) const
+{
+ SCM name = scm_eval (gh_list (gh_symbol2scm ("user-pitch-name"), ly_quote_scm (pitch2scm (p)), SCM_UNDEFINED));
- //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];
+ if (name != SCM_UNSPECIFIED)
+ {
+ return ly_text2molecule (name);
+ }
+
+ Molecule mol = lookup_l ()->text ("", p.str ().left_str (1).upper_str (), paper_l ());
+ if (p.accidental_i_)
+ // urg, how to select the feta-1 font?
+ mol.add_at_edge (X_AXIS, RIGHT,
+ lookup_l ()->accidental (p.accidental_i_, 0), 0);
+ return mol;
+}
+
+Musical_pitch
+diff_pitch (Musical_pitch tonic, Musical_pitch p)
+{
+ Musical_pitch diff (p.notename_i_ - tonic.notename_i_,
+ p.accidental_i_ - tonic.accidental_i_,
+ p.octave_i_ - tonic.octave_i_);
+
+ while (diff.notename_i_ >= 7)
+ {
+ diff.notename_i_ -= 7;
+ diff.octave_i_ ++;
+ }
+ while (diff.notename_i_ < 0)
+ {
+ diff.notename_i_ += 7;
+ diff.octave_i_ --;
+ }
+
+ diff.accidental_i_ -= (tonic.semitone_pitch () + diff.semitone_pitch ())
+ - p.semitone_pitch ();
+
+ return diff;
+}
+bool
+Chord::user_chord_name (Array<Musical_pitch> pitch_arr, Chord_name* name_p) const
+{
+ SCM chord = SCM_EOL;
+ Array<Musical_pitch> chord_type = pitch_arr;
+ rebuild_transpose (&chord_type, diff_pitch (pitch_arr[0], Musical_pitch (0)), false);
+
+ for (int i= chord_type.size (); i--; )
+ chord = gh_cons (pitch2scm (chord_type[i]), chord);
+
+ SCM name = scm_eval (gh_list (gh_symbol2scm ("user-chord-name"), ly_quote_scm (chord), SCM_UNDEFINED));
+ if (name != SCM_UNSPECIFIED)
+ {
+ name_p->modifier_mol = ly_text2molecule (gh_car (name));
+ name_p->addition_mol = ly_text2molecule (gh_cdr (name));
+ return true;
+ }
+ return false;
+}
+
+void
+Chord::banter (Array<Musical_pitch> pitch_arr, Chord_name* name_p) const
+{
Array<Musical_pitch> add_arr;
Array<Musical_pitch> sub_arr;
- find_additions_and_subtractions (&add_arr, &sub_arr);
+ find_additions_and_subtractions (pitch_arr, &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);
+ Musical_pitch tonic = pitch_arr[0];
+ rebuild_transpose (&scale, tonic, true);
- bool has3m_b = false;
- bool has4_b = false;
- bool has5m_b = false;
- String str;
- String minor_str;
+ /*
+ Does chord include this step? -1 if flat
+ */
+ int has[16];
+ for (int i=0; i<16; i++)
+ has[i] = 0;
+
+ String mod_str;
+ String add_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 < 16) && (has[step] != -1))
+ has[step] = accidental == -1 ? -1 : 1;
if ((step == 3) && (accidental == -1))
{
- minor_str = "m";
- has3m_b = true;
+ mod_str = "m";
}
/*
- have Cdim rather than Cm5-, even if it's a prefix
+ urg.
+ This routine gets a lot simpler, if we don't try to be catch
+ the 'dim' chords. However, we'll have to list every exceptional
+ 'dim' chord in scm: otherwise we'll get stuff like Cdim7-, iso
+ Cdim7, etc
*/
- else if ((step == 5) && (accidental == -1) && has3m_b)
+#ifdef SMART_DIM
+ else if ((step == 5) && (accidental == -1) && (has[3] == -1))
{
- minor_str = "dim";
- has5m_b = true;
+ mod_str = "dim";
}
+#endif
else if (accidental
- || (!(step % 2) || ((i + 1 == add_arr.size ()) && (step > 5))))
+ || (!(step % 2)
+ || ((i == add_arr.size () - 1) && (step > 5))))
{
- str += sep_str;
+ add_str += sep_str;
sep_str = "/";
if ((step == 7) && (accidental == 1))
{
- str += "maj7";
+ add_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
+#ifdef SMART_DIM
+ {
+ if ((step % 2) && (accidental == -1)
+ && (has[3] == -1) && (has[5] == -1))
+ {
+ if (i != add_arr.size () - 1)
sep_str = "";
+ else
+ add_str += to_str (step);
}
else
+#endif
{
- str += to_str (step);
- if (accidental)
- str += accidental < 0 ? "-" : "+";
+ add_str += to_str (step);
+ if (accidental)
+ add_str += accidental < 0 ? "-" : "+";
}
- }
+#ifdef SMART_DIM
+ }
+#endif
}
}
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 additions include 2 or 4, assume sus2/4 and don't display 'no3'
*/
- 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))
+ if (!((step == 3) && (has[2] || has[4])))
{
- str += sep_str + "no" + to_str (step);
+ add_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_)
+ if (mod_str.length_i ())
+ name_p->modifier_mol.add_at_edge (X_AXIS, RIGHT,
+ lookup_l ()->text ("roman", mod_str, paper_l ()), 0);
+ if (add_str.length_i ())
{
- inversion_str = inversion_p_->str ();
- inversion_str = "/" + inversion_str.left_str (1).upper_str ()
- + acc[inversion_p_->accidental_i_ + 2];
+ if (!name_p->addition_mol.empty_b ())
+ add_str = "/" + add_str;
+ name_p->addition_mol.add_at_edge (X_AXIS, RIGHT,
+ lookup_l ()->text ("script", add_str, paper_l ()), 0);
}
-
- 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)
{
bass.octave_i_--;
pitch_arr_p->insert (bass, 0);
}
+
+Molecule*
+Chord::do_brew_molecule_p () const
+{
+ Musical_pitch tonic = pitch_arr_[0];
+
+ Chord_name name;
+ name.tonic_mol = pitch2molecule (tonic);
+
+ /*
+ if user has explicitely listed chord name, use that
+
+ TODO
+ urg
+ maybe we should check all sub-lists of pitches, not
+ just full list and base triad?
+ */
+ if (!user_chord_name (pitch_arr_, &name))
+ {
+ /*
+ else, check if user has listed base triad
+ use user base name and add banter for remaining part
+ */
+ if ((pitch_arr_.size () > 2)
+ && user_chord_name (pitch_arr_.slice (0, 3), &name))
+ {
+ Array<Musical_pitch> base = base_arr (tonic);
+ base.concat (pitch_arr_.slice (3, pitch_arr_.size ()));
+ banter (base, &name);
+ }
+ /*
+ else, use pure banter
+ */
+ else
+ {
+ banter (pitch_arr_, &name);
+ }
+ }
+
+ if (inversion_p_)
+ {
+ name.inversion_mol = lookup_l ()->text ("", "/", paper_l ());
+ // zucht const&
+ Molecule mol = pitch2molecule (*inversion_p_);
+ name.inversion_mol.add_at_edge (X_AXIS, RIGHT, mol, 0);
+ }
+
+ if (bass_p_)
+ {
+ name.bass_mol = lookup_l ()->text ("", "/", paper_l ());
+ Molecule mol = pitch2molecule (*bass_p_);
+ name.bass_mol.add_at_edge (X_AXIS, RIGHT, mol, 0);
+ }
+
+ // urg, howto get a good superscript_y?
+ Real super_y = lookup_l ()->text ("", "x", paper_l ()).dim_.y ().length ()/2;
+ if (!name.addition_mol.empty_b ())
+ name.addition_mol.translate (Offset (0, super_y));
+
+ Molecule* mol_p = new Molecule;
+ mol_p->add_at_edge (X_AXIS, RIGHT, name.tonic_mol, 0);
+ // huh?
+ if (!name.modifier_mol.empty_b ())
+ mol_p->add_at_edge (X_AXIS, RIGHT, name.modifier_mol, 0);
+ if (!name.addition_mol.empty_b ())
+ mol_p->add_at_edge (X_AXIS, RIGHT, name.addition_mol, 0);
+ if (!name.inversion_mol.empty_b ())
+ mol_p->add_at_edge (X_AXIS, RIGHT, name.inversion_mol, 0);
+ if (!name.bass_mol.empty_b ())
+ mol_p->add_at_edge (X_AXIS, RIGHT, name.bass_mol, 0);
+ return mol_p;
+}
+
+void
+Chord::do_print () const
+{
+#ifndef NPRINT
+ //DEBUG_OUT << "chord = " ...
+#endif
+}