[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] Added chromatic ledger and internal ledger lines. Sample test fi
From: |
Kevin Dalley |
Subject: |
[PATCH] Added chromatic ledger and internal ledger lines. Sample test file is |
Date: |
Mon, 05 Mar 2007 23:59:31 -0800 |
User-agent: |
Gnus/5.110006 (No Gnus v0.6) XEmacs/21.4.19 (linux) |
This patch includes chromatic staffs which place the each of the 12
semitones of an octave on a different vertical position on the staff.
I have examples of the LilyPond code and output here:
http://www.kelphead.org/chromatic/
This code also allows the placement of ledger lines internal to the
staff, which is in ledger-line-spanner.cc.
I hope that this patch comes close to meeting your standards. I
refactored the ledger-line-spanner.cc a bit to reduce code duplication.
>From f12dff06a034c765190ed51e49a0040a7ad74ca7 Mon Sep 17 00:00:00 2001
From: Kevin Dalley <address@hidden>
Date: Mon, 5 Mar 2007 23:43:20 -0800
Subject: [PATCH] Added chromatic ledger and internal ledger lines. Sample test
file is
input/test/chromatic-scales.ly.
---
Documentation/topdocs/AUTHORS.texi | 2 +
THANKS | 2 +-
input/test/chromatic-scales.ly | 35 ++++
lily/ledger-line-spanner.cc | 305 +++++++++++++++++++++++++++++++-----
lily/note-heads-engraver.cc | 55 ++++++-
lily/staff-symbol.cc | 1 +
scm/define-context-properties.scm | 1 +
scm/define-grob-properties.scm | 1 +
8 files changed, 357 insertions(+), 45 deletions(-)
diff --git a/Documentation/topdocs/AUTHORS.texi
b/Documentation/topdocs/AUTHORS.texi
index db20189..905abf4 100644
--- a/Documentation/topdocs/AUTHORS.texi
+++ b/Documentation/topdocs/AUTHORS.texi
@@ -29,6 +29,8 @@ al-niente hairpins.
@item @email{benkop@@freestart.hu,Pal Benko},
Ancient notation.
address@hidden @email{kevin@@kelphead.org,Kevin Dalley},
+ Chromatic staff, staff-line-layout, and internal ledger lines.
@item @email{david.feuer@@gmail.com, David Feuer},
PS output code refactoring.
@item @email{bernard@@fong-hurley.org.uk, Bernard Hurley},
diff --git a/THANKS b/THANKS
index 3862361..f750419 100644
--- a/THANKS
+++ b/THANKS
@@ -19,7 +19,7 @@ Erlend Aasland
Guido Amoruso
Heikki Junes
Joe Neeman
-
+Kevin Dalley
SPONSORS
diff --git a/input/test/chromatic-scales.ly b/input/test/chromatic-scales.ly
new file mode 100644
index 0000000..dd75c70
--- /dev/null
+++ b/input/test/chromatic-scales.ly
@@ -0,0 +1,35 @@
+\version "2.10"
+\include "english.ly"
+% This shows how to use internal-ledger-lines and staff-line-layout
+% to produce alternative chromatic notation.
+% This notation is 6-6 Tetragram by Richard Parncutt
+% For more information,
+% see http://web.syr.edu/~pwmorris/mnma/gallery/4LineNotations.html
+
+scales = \relative {
+ a, as b c cs d ds e f fs g gs
+ a as b c cs d ds e f fs g gs
+ a as b c cs d ds e f fs g gs
+ a
+}
+
+\new Staff \with {
+ \remove "Accidental_engraver"
+ staff-line-layout = #'semitone
+ middleCPosition = #-2
+ clefGlyph = #"clefs.G"
+ clefPosition = #(+ -2 7)
+}
+{
+ \override Staff.StaffSymbol #'line-count = #8
+ \override Staff.StaffSymbol #'line-positions = #'(-9 -7 -5 -3 3 5 7 9)
+ \override Staff.StaffSymbol #'internal-ledger-lines = #'((-1 1))
+ \time 4/4
+ <<
+ \scales
+ \context NoteNames {
+ \set printOctaveNames= ##f
+ \scales
+ }
+ >>
+}
diff --git a/lily/ledger-line-spanner.cc b/lily/ledger-line-spanner.cc
index bf7444d..8401d2d 100644
--- a/lily/ledger-line-spanner.cc
+++ b/lily/ledger-line-spanner.cc
@@ -7,6 +7,7 @@
*/
#include <map>
+#include <set>
using namespace std;
#include "item.hh"
@@ -18,6 +19,104 @@ using namespace std;
#include "pointer-group-interface.hh"
#include "paper-column.hh"
+
+
+struct Ledger_request
+{
+ Interval ledger_extent_;
+ Interval head_extent_;
+ /* non-negative position, direction is removed */
+ int position_;
+ bool excentric_;
+ Ledger_request ()
+ {
+ ledger_extent_.set_empty ();
+ head_extent_.set_empty ();
+ position_ = 0;
+ }
+};
+
+typedef map < int, Drul_array<Ledger_request> > Ledger_requests;
+typedef map <int, Ledger_request> Ledger_requests_internal;
+
+/* This consists of a group of ledger lines internal to the staff.
+ There should be no staff lines between these ledger lines
+ */
+class Internal_ledgers
+{
+public:
+ Internal_ledgers():
+ halfspace_(1)
+ {
+ }
+ void set_halfspace(const Real& halfspace)
+ {
+ halfspace_ = halfspace;
+ }
+ /**
+ * add new ledger line at \a new_ledger
+ *
+ * @param newLedger new ledger position
+ *
+ */
+ void add_ledger(int new_ledger)
+ {
+ ledgers_.insert(new_ledger);
+ }
+
+ /** must be performed before using contains */
+ void calculate_extent()
+ {
+ ledger_extent_ = Interval(*min_element(ledgers_.begin(),
+ ledgers_.end())/halfspace_ - 1,
+ *max_element(ledgers_.begin(),
+ ledgers_.end())/halfspace_ + 1);
+ }
+ /**
+ *
+ *
+ * @param pos
+ *
+ * @return true if \a pos is contain in ledger
+ */
+ bool contains(int pos) const
+ {
+ return ledger_extent_.contains(pos/halfspace_);
+ }
+ const set<int>& ledger_set() const
+ {
+ return ledgers_;
+ }
+private:
+ Interval ledger_extent_;
+ set<int> ledgers_;
+ /** set halfspace for rounding ledger extent */
+ Real halfspace_;
+};
+
+
+/**
+ *
+ *
+ * @param pos
+ * @param internal_ledgers_container
+ *
+ * @return true if \a pos is contained in at least one item in Internal_ledgers
+ */
+bool contains(int pos, const vector<Internal_ledgers>&
internal_ledgers_container)
+{
+ for (vector<Internal_ledgers>::const_iterator internal_ledgers =
internal_ledgers_container.begin();
+ internal_ledgers != internal_ledgers_container.end();
+ ++internal_ledgers)
+ {
+ if ((*internal_ledgers).contains(pos))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
struct Ledger_line_spanner
{
DECLARE_SCHEME_CALLBACK (print, (SCM));
@@ -28,8 +127,21 @@ struct Ledger_line_spanner
Real, Real,
Interval x_extent,
Real left_shorten);
-
+ static Stencil brew_internal_ledger_lines (const Internal_ledgers&
internal_ledgers,
+ Real, Real,
+ Interval x_extent,
+ Real left_shorten);
static bool has_interface (Grob *);
+ /* returns ledger_size and left_shorten, given other values
+ * helper method for brew_ledger_lines
+ */
+ static void find_ledger_size(const Item *head, Grob *common[],
+ Real length_fraction,
+ Ledger_request& req,
+ Interval& ledger_size,
+ Real& left_shorten
+ );
+
};
Stencil
@@ -44,6 +156,7 @@ Ledger_line_spanner::brew_ledger_lines (Grob *staff,
int line_count = (staff_extent.contains (pos)
? 0
: sign (pos) * int (rint(pos - staff_extent[Direction
(sign (pos))])) / 2);
+
Stencil stencil;
if (line_count)
{
@@ -73,7 +186,40 @@ Ledger_line_spanner::brew_ledger_lines (Grob *staff,
stencil.add_stencil (ledger_line);
}
}
-
+
+ return stencil;
+}
+/** extra lines for internal ledger lines */
+Stencil
+Ledger_line_spanner::brew_internal_ledger_lines (const Internal_ledgers&
internal_ledgers,
+ Real halfspace,
+ Real ledgerlinethickness,
+ Interval x_extent,
+ Real left_shorten)
+{
+ Stencil stencil;
+ /* halfspace is 1/2 of staff-space */
+ Real blotdiameter = ledgerlinethickness;
+ Interval y_extent
+ = Interval (-0.5 * (ledgerlinethickness),
+ +0.5 * (ledgerlinethickness));
+ Stencil proto_ledger_line
+ = Lookup::round_filled_box (Box (x_extent, y_extent), blotdiameter);
+ x_extent[LEFT] += left_shorten;
+ Stencil proto_first_line
+ = Lookup::round_filled_box (Box (x_extent, y_extent), blotdiameter);
+ const set<int>& ledgers = internal_ledgers.ledger_set();
+ for (set<int>::const_iterator currentLedger = ledgers.begin();
+ currentLedger != ledgers.end();
+ ++currentLedger)
+ {
+ int pos = *currentLedger;
+ Real offs = pos * halfspace;
+ Stencil ledger_line(proto_ledger_line);
+ // Stencil ledger_line(proto_first_line);
+ ledger_line.translate_axis(offs, Y_AXIS);
+ stencil.add_stencil (ledger_line);
+ }
return stencil;
}
@@ -181,26 +327,50 @@ Ledger_line_spanner::set_spacing_rods (SCM smob)
return SCM_UNSPECIFIED;
}
-struct Ledger_request
+/*
+ * Calculate
+ * ledger_size
+ * left_shorten
+ */
+void
+Ledger_line_spanner::find_ledger_size(const Item *head, Grob *common[],
+ Real length_fraction,
+ Ledger_request& req,
+ Interval& ledger_size,
+ Real& left_shorten
+ )
{
- Interval ledger_extent_;
- Interval head_extent_;
- int position_;
- bool excentric_;
- Ledger_request ()
- {
- ledger_extent_.set_empty ();
- head_extent_.set_empty ();
- position_ = 0;
- }
-};
+
+ Interval head_size = head->extent (common[X_AXIS], X_AXIS);
+ ledger_size = head_size;
+ ledger_size.widen (ledger_size.length () * length_fraction);
-typedef map < int, Drul_array<Ledger_request> > Ledger_requests;
+ Interval max_size = req.ledger_extent_;
+ ledger_size.intersect (max_size);
+ left_shorten = 0.0;
+ if (Grob *g = unsmob_grob (head->get_object ("accidental-grob")))
+ {
+ Interval accidental_size = g->extent (common[X_AXIS], X_AXIS);
+ Real d
+ = linear_combination (Drul_array<Real> (accidental_size[RIGHT],
+ head_size[LEFT]),
+ 0.0);
+
+ left_shorten = max (-ledger_size[LEFT] + d, 0.0);
+
+ /*
+ TODO: shorten 2 ledger lines for the case natural +
+ downstem.
+ */
+ }
+}
+
/*
TODO: ledger share a lot of info. Lots of room to optimize away
common use of objects/variables.
*/
+
MAKE_SCHEME_CALLBACK (Ledger_line_spanner, print, 1);
SCM
Ledger_line_spanner::print (SCM smob)
@@ -240,12 +410,42 @@ Ledger_line_spanner::print (SCM smob)
}
Ledger_requests reqs;
+ Ledger_requests_internal reqs_internal;
+
+ // add internal ledger lines to list
+ vector<Internal_ledgers> internal_ledgers_container;
+ SCM internal_ledgers = staff->get_property("internal-ledger-lines");
+ set<int> ledger_set;
+ if (scm_is_pair(internal_ledgers))
+ {
+ for (SCM s = internal_ledgers; scm_is_pair (s);
+ s = scm_cdr (s))
+ {
+ SCM car = scm_car(s);
+ Internal_ledgers internal_ledgers;
+ internal_ledgers.set_halfspace(halfspace);
+ // ignore if s2 is not car
+ for (SCM s2 = car; scm_is_pair (s2);
+ s2 = scm_cdr (s2))
+ {
+ int pos = scm_to_int (scm_car(s2));
+ // ledger_set.insert(pos);
+ internal_ledgers.add_ledger(pos);
+ }
+ internal_ledgers.calculate_extent();
+ internal_ledgers_container.push_back(internal_ledgers);
+ }
+
+ }
+
+
+
for (vsize i = heads.size (); i--;)
{
Item *h = dynamic_cast<Item *> (heads[i]);
int pos = Staff_symbol_referencer::get_rounded_position (h);
- if (pos && !staff_extent.contains (pos))
+ if (pos != 0 && !staff_extent.contains (pos))
{
Interval head_extent = h->extent (common[X_AXIS], X_AXIS);
Interval ledger_extent = head_extent;
@@ -259,6 +459,22 @@ Ledger_line_spanner::print (SCM smob)
reqs[rank][vdir].position_
= vdir * max (vdir * reqs[rank][vdir].position_, vdir * pos);
}
+
+ if (contains(pos, internal_ledgers_container))
+ {
+ Interval head_extent = h->extent (common[X_AXIS], X_AXIS);
+ Interval ledger_extent = head_extent;
+ ledger_extent.widen (length_fraction * head_extent.length ());
+
+ Direction vdir = Direction (sign (pos));
+ int rank = h->get_column ()->get_rank ();
+
+ reqs_internal[rank].ledger_extent_.unite (ledger_extent);
+ reqs_internal[rank].head_extent_.unite (head_extent);
+ reqs_internal[rank].position_
+ = vdir * max (vdir * reqs_internal[rank].position_, vdir * pos);
+ }
+
}
// determine maximum size for non-colliding ledger.
@@ -312,30 +528,14 @@ Ledger_line_spanner::print (SCM smob)
int pos = Staff_symbol_referencer::get_rounded_position (h);
if (!staff_extent.contains (pos - sign (pos)))
{
- Interval head_size = h->extent (common[X_AXIS], X_AXIS);
- Interval ledger_size = head_size;
- ledger_size.widen (ledger_size.length () * length_fraction);
-
- Interval max_size = reqs[h->get_column ()->get_rank ()]
- [Direction (sign (pos))].ledger_extent_;
+ Interval ledger_size;
+ Real left_shorten;
- ledger_size.intersect (max_size);
- Real left_shorten = 0.0;
- if (Grob *g = unsmob_grob (h->get_object ("accidental-grob")))
- {
- Interval accidental_size = g->extent (common[X_AXIS], X_AXIS);
- Real d
- = linear_combination (Drul_array<Real> (accidental_size[RIGHT],
- head_size[LEFT]),
- 0.0);
-
- left_shorten = max (-ledger_size[LEFT] + d, 0.0);
-
- /*
- TODO: shorten 2 ledger lines for the case natural +
- downstem.
- */
- }
+ find_ledger_size(h, common, length_fraction,
+ reqs[h->get_column ()->get_rank ()]
+ [Direction (sign (pos))],
+ ledger_size,
+ left_shorten);
ledgers.add_stencil (brew_ledger_lines (staff, pos, staff_extent,
halfspace,
@@ -343,6 +543,30 @@ Ledger_line_spanner::print (SCM smob)
ledger_size,
left_shorten));
}
+
+ /* handle internal ledger lines */
+ for (vector<Internal_ledgers>::const_iterator internal_ledgers =
internal_ledgers_container.begin();
+ internal_ledgers != internal_ledgers_container.end();
+ ++internal_ledgers)
+ {
+ if ((*internal_ledgers).contains(pos))
+ {
+ Interval ledger_size;
+ Real left_shorten;
+
+ find_ledger_size(h, common, length_fraction,
+ reqs_internal[h->get_column ()->get_rank ()],
+ ledger_size,
+ left_shorten);
+
+ ledgers.add_stencil (brew_internal_ledger_lines
(*internal_ledgers,
+ halfspace,
+
ledgerlinethickness,
+ ledger_size,
+ left_shorten));
+ }
+ }
+
}
ledgers.translate_axis (-me->relative_coordinate (common[X_AXIS], X_AXIS),
@@ -363,7 +587,8 @@ ADD_INTERFACE (Ledger_line_spanner,
"thickness "
"minimum-length-fraction "
"length-fraction "
- "gap");
+ "gap "
+ "internal-ledger-lines");
struct Ledgered_interface
{
diff --git a/lily/note-heads-engraver.cc b/lily/note-heads-engraver.cc
index 6c065af..4e9b0fe 100644
--- a/lily/note-heads-engraver.cc
+++ b/lily/note-heads-engraver.cc
@@ -22,6 +22,35 @@ using namespace std;
#include "translator.icc"
+class Layout_pos
+{
+public:
+ virtual int pos(Pitch* pit) = 0;
+};
+
+class Layout_pos_traditional : public Layout_pos
+{
+public:
+ virtual int pos(Pitch* pit)
+ {
+ return pit ? pit->steps () : 0;
+ }
+};
+
+static Layout_pos_traditional layout_pos_traditional;
+
+class Layout_pos_semitone : public Layout_pos
+{
+public:
+ virtual int pos(Pitch* pit)
+ {
+ return pit ? pit->semitone_pitch() : 0;
+ }
+};
+
+static Layout_pos_semitone layout_pos_semitone;
+
+
class Note_heads_engraver : public Engraver
{
vector<Item*> notes_;
@@ -50,6 +79,18 @@ Note_heads_engraver::listen_note (Stream_event *ev)
void
Note_heads_engraver::process_music ()
{
+ Layout_pos *layout_pos = &layout_pos_traditional;
+ SCM layout_property = get_property("staff-line-layout");
+ if (layout_property)
+ {
+ if (ly_is_equal(layout_property, ly_symbol2scm("traditional"))){
+ layout_pos = &layout_pos_traditional;
+ }
+ else if (ly_is_equal(layout_property, ly_symbol2scm("semitone"))){
+ layout_pos = &layout_pos_semitone;
+ }
+ }
+
for (vsize i = 0; i < note_evs_.size (); i++)
{
Stream_event *ev = note_evs_[i];
@@ -63,11 +104,16 @@ Note_heads_engraver::process_music ()
ev->origin ()->warning (_ ("NoteEvent without pitch"));
#endif
- int pos = pit ? pit->steps () : 0;
SCM c0 = get_property ("middleCPosition");
+ int middleC;
if (scm_is_number (c0))
- pos += scm_to_int (c0);
-
+ middleC = scm_to_int(c0);
+ else
+ middleC = 0;
+ int pos = layout_pos->pos(pit);
+
+ pos += middleC;
+
note->set_property ("staff-position", scm_from_int (pos));
/*
@@ -106,5 +152,6 @@ ADD_TRANSLATOR (Note_heads_engraver,
/* doc */ "Generate noteheads.",
/* create */
"NoteHead ",
- /* read */ "middleCPosition",
+ /* read */ "middleCPosition "
+ "staff-line-layout",
/* write */ "");
diff --git a/lily/staff-symbol.cc b/lily/staff-symbol.cc
index 6edb1f9..554b2e2 100644
--- a/lily/staff-symbol.cc
+++ b/lily/staff-symbol.cc
@@ -186,4 +186,5 @@ ADD_INTERFACE (Staff_symbol, "staff-symbol-interface",
"staff-space "
"thickness "
"width "
+ "internal-ledger-lines "
);
diff --git a/scm/define-context-properties.scm
b/scm/define-context-properties.scm
index fe32b4e..bf781bb 100644
--- a/scm/define-context-properties.scm
+++ b/scm/define-context-properties.scm
@@ -372,6 +372,7 @@ up the interpretation phase. This speeds up debugging large
scores.")
(squashedPosition ,integer? " Vertical position of
squashing for @internalsref{Pitch_squash_engraver}.")
+ (staff-line-layout ,symbol? "Layout of staff lines, 'traditional, or
'semitone.")
(stringNumberOrientations ,list? "See @code{fingeringOrientations}")
(strokeFingerOrientations ,list? "See @code{fingeringOrientations}")
(stringOneTopmost ,boolean? "Whether the 1st string is printed on the
diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm
index dddcef9..4c79a53 100644
--- a/scm/define-grob-properties.scm
+++ b/scm/define-grob-properties.scm
@@ -204,6 +204,7 @@ and slur ignore eachother.")
set beam/slur quant to this position, and print the respective scores.")
(inspect-index ,integer? "If debugging is set,
set beam/slur configuration to this index, and print the respective scores.")
+ (internal-ledger-lines ,list? "Ledger lines placed between first and last
lines of staff.")
(implicit ,boolean? "Is this an implicit bass figure?")
(keep-inside-line ,boolean? "If set, this column cannot have
things sticking into the margin.")
--
1.4.4.4
- [PATCH] Added chromatic ledger and internal ledger lines. Sample test file is,
Kevin Dalley <=