+2003-01-14 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+ * lily/cluster-engraver.cc: clean up Cluster engraver
+
+ * lily/cluster.cc (brew_molecule): cleaned up Cluster code and
+ Engraver. Use Note_column to compute Y positions and deal with
+ line break stuff.
+
+2003-01-13 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+ * lily/stem.cc: move french-beaming to stem.
+
2003-01-13 Heikki Junes <hjunes@cc.hut.fi>
* lilypond-font-lock.el: fontify all durations in chords.
2003-01-12 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+ * lily/vaticana-ligature-engraver.cc (finish_primitive): compile fixes.
+
* lily/gregorian-ligature.cc: new file
* lily/*: the Great 2003 search & replace.
@menu
* Creating contexts::
* Default contexts::
+* Context evaluation::
* Context properties::
* Engravers and performers::
* Changing context definitions::
sequential music is also interpreted with the same Thread, Voice, and
Staff context, putting the notes on the same staff, in the same voice.
+@node Context evaluation
+@subsection Context evaluation
+
+Scheme code can be used to modify contexts. The syntax for this is
+
+@example
+ \applycontext @var{function}
+@end example
+
+@var{function} should be a Scheme function taking a single argument,
+being the context to apply it with. The following code will print the
+current bar number on the standard output during the compile.
+
+@example
+ \applycontext
+ #(lambda (tr)
+ (format #t "\nWe were called in barnumber ~a.\n"
+ (ly:get-context-property tr 'currentBarNumber)))
+@end example
+
+
+
+
+
@node Context properties
@subsection Context properties
+
Notation contexts have properties. These properties are from
the @file{.ly} file using the following expression:
@cindex @code{\property}
* Completely rewritten text formatting support. It is implemented in a
completely modular way.
+
** Better chord names.
** Texts on multimeasure rests can be set by the user.
** Cluster support. Syntax:
- NOTE-\openCluster
+ NOTE-\startCluster
+
..
- NOTE-\closeCluster
+ NOTE-\stopCluster
** Beat grouping indications. Syntax:
..
NOTE-\groupClose
-
+** Gregorian ligatures.
New features in 1.6 since 1.4
%% todo: should put something interesting in the .tex output.
- \applycontext #(lambda (tr)
- (let* ((bn (ly:get-context-property tr 'currentBarNumber)))
- (if (= bn 3)
- #t
- (format #t "We were called in ~a" bn))
- ))
-
+ \applycontext
+ #(lambda (tr)
+ (format #t "\nWe were called in barnumber ~a.\n"
+ (ly:get-context-property tr 'currentBarNumber)))
c1 c1
}}
\property Staff.Accidental \set #'transparent = ##t
\property Voice.Cluster \set #'padding = #0.25
\property Voice.Cluster \set #'shape = #'ramp
- c4 f4
- \startCluster
+ c4 f4-\startCluster
a4 <<e d'>>4 | \break
%%% do not try something like: < { g8 e8 } a4 >
%%% instead, do the following: << g a >>8 << e a >>8
<< g a >>8 << e a >>8 a4 c1 << d b >>4 e4 |
- c4 \stopCluster a4 f4 g4 a4
+ c4-\stopCluster a4 f4 g4 a4
}
}
linewidth = 15.0 \cm
}
}
-%% new-chords-done %%
\ No newline at end of file
+%% new-chords-done %%
if (Stem::invisible_b (s))
continue;
+
+ bool french = to_boolean (s->get_grob_property ("french-beaming"));
Real stem_y = calc_stem_y (me, s, common,
xl, xr,
pos, french && i > 0&& (i < stems.size () -1));
"the ideal slope, how close the result is to the ideal stems, etc.). We "
"take the best scoring combination. "
,
- "knee french-beaming position-callbacks concaveness-gap concaveness-threshold dir-function quant-score auto-knee-gap gap chord-tremolo beamed-stem-shorten shorten least-squares-dy damping flag-width-function neutral-direction positions space-function thickness");
+ "knee position-callbacks concaveness-gap concaveness-threshold dir-function quant-score auto-knee-gap gap chord-tremolo beamed-stem-shorten shorten least-squares-dy damping flag-width-function neutral-direction positions space-function thickness");
cluster-engraver.cc -- implement Cluster_engraver
(c) 2002--2003 Juergen Reuter <reuter@ipd.uka.de>
+
+ Han-Wen Nienhuys <hanwen@cs.uu.nl>
*/
#include "engraver.hh"
#include "note-head.hh"
#include "protected-scm.hh"
#include "warn.hh"
+#include "note-column.hh"
+#include "group-interface.hh"
class Cluster_engraver : public Engraver
{
protected:
TRANSLATOR_DECLARATIONS(Cluster_engraver);
- virtual void start_translation_timestep ();
virtual bool try_music (Music *);
virtual void process_music ();
virtual void acknowledge_grob (Grob_info);
private:
Drul_array<Music*> reqs_drul_;
- Pitch pitch_min_, pitch_max_;
+
Spanner *cluster_;
- Protected_scm columns_scm_;
};
-void reset_min_max (Pitch *pitch_min, Pitch *pitch_max)
-{
- /*
- * (pitch_min > pitch_max) means that pitches are not yet
- * initialized
- */
- *pitch_min = Pitch (0, 0, +1);
- *pitch_max = Pitch (0, 0, -1);
-}
-
Cluster_engraver::Cluster_engraver ()
{
cluster_ = 0;
- columns_scm_ = SCM_EOL;
reqs_drul_[LEFT] = reqs_drul_[RIGHT] = 0;
}
{
cluster_->suicide ();
cluster_ = 0;
- columns_scm_ = SCM_EOL;
}
}
else if (m->is_mus_type ("cluster-event"))
{
Direction d = to_dir (m->get_mus_property ("span-direction"));
+
reqs_drul_[d] = m;
return true;
}
}
else
{
- SCM basicProperties = get_property ("Cluster");
- cluster_ = new Spanner (basicProperties);
- columns_scm_ = SCM_EOL;
+ cluster_ = new Spanner (get_property ("Cluster"));
Grob *bound = unsmob_grob (get_property ("currentMusicalColumn"));
cluster_->set_bound (LEFT, bound);
- announce_grob (cluster_, bound->self_scm ());
+ announce_grob (cluster_, reqs_drul_[START]->self_scm ());
}
reqs_drul_[START] = 0;
}
}
-void
-Cluster_engraver::start_translation_timestep ()
-{
- reset_min_max (&pitch_min_, &pitch_max_);
-}
void
Cluster_engraver::stop_translation_timestep ()
{
- if (cluster_)
+ if (reqs_drul_[STOP])
{
- SCM column_scm = get_property ("currentMusicalColumn");
- if (column_scm == SCM_EOL)
- {
- programming_error("failed retrieving current column");
- }
- else
- {
- if (Pitch::compare (pitch_min_, pitch_max_) <= 0)
- {
- Real y_bottom = 0.5 * pitch_min_.steps ();
- SCM c0 = get_property ("centralCPosition");
- if (gh_number_p (c0))
- y_bottom += 0.5 * gh_scm2int (c0);
- else
- programming_error ("Cluster_engraver: failed evaluating c0");
- Real y_top = y_bottom +
- 0.5 * (pitch_max_.steps () - pitch_min_.steps ());
- column_scm = Protected_scm (column_scm);
- SCM segment = scm_list_n (column_scm,
- gh_double2scm (y_bottom),
- gh_double2scm (y_top),
- SCM_UNDEFINED);
- segment = scm_list_n (segment, SCM_UNDEFINED);
- columns_scm_ = (columns_scm_ != SCM_EOL) ?
- gh_append2 (columns_scm_, segment) : segment;
- }
- else
- {
- /* This timestep is caused by a different voice of the
- same staff and hence should be ignored. */
- }
- }
-
- if (reqs_drul_[STOP])
- {
- reqs_drul_[STOP] = 0;
- cluster_->set_grob_property ("segments", columns_scm_);
- typeset_grob (cluster_);
- cluster_ = 0;
- columns_scm_ = SCM_EOL;
- }
+ reqs_drul_[STOP] = 0;
+ typeset_grob (cluster_);
+ cluster_ = 0;
}
}
void
Cluster_engraver::acknowledge_grob (Grob_info info)
{
- Item *item = dynamic_cast <Item *>(info.grob_);
- if (item)
+ if (cluster_ && Note_column::has_interface (info.grob_))
{
- if (Note_head::has_interface (info.grob_))
- {
- Music *nr = info.music_cause ();
- if (nr && nr->is_mus_type ("note-event"))
- {
- Pitch pitch = *unsmob_pitch (nr->get_mus_property ("pitch"));
- if (Pitch::compare (pitch_min_, pitch_max_) > 0) // already init'd?
- {
- // not yet init'd; use current pitch to init min/max
- pitch_min_ = pitch;
- pitch_max_ = pitch;
- }
- else if (Pitch::compare (pitch, pitch_max_) > 0) // new max?
- {
- pitch_max_ = pitch;
- }
- else if (Pitch::compare (pitch, pitch_min_) < 0) // new min?
- {
- pitch_min_ = pitch;
- }
- }
- }
+ Pointer_group_interface::add_grob (cluster_, ly_symbol2scm ("columns"), info.grob_);
}
}
/* descr */ "engraves a cluster",
/* creats*/ "Cluster",
/* accepts */ "cluster-event",
-/* acks */ "note-head-interface",
+/* acks */ "note-column-interface",
/* reads */ "",
/* write */ "");
source file of the GNU LilyPond music typesetter
(c) 2002--2003 Juergen Reuter <reuter@ipd.uka.de>
+
+ Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
*/
#include <stdio.h>
#include "interval.hh"
#include "paper-def.hh"
#include "paper-column.hh"
+#include "note-column.hh"
/*
* TODO: Add support for cubic spline segments.
Item *left_bound = spanner->get_bound (LEFT);
Item *right_bound = spanner->get_bound (RIGHT);
- bool right_broken = right_bound->break_status_dir () != CENTER;
Grob *common = left_bound->common_refpoint (right_bound, X_AXIS);
-
- Grob *column = 0;
+ SCM cols =me->get_grob_property ("columns");
+ if (!gh_pair_p (cols))
+ {
+ me->warning ("junking empty cluster");
+ me->suicide ();
+
+ return SCM_EOL;
+ }
+ common = common_refpoint_of_list (cols, common, X_AXIS);
Array<Offset> bottom_points;
Array<Offset> top_points;
- bottom_points.clear ();
- top_points.clear ();
- SCM column_scm = SCM_EOL;
- SCM columns_scm = me->get_grob_property ("segments");
- if (columns_scm == SCM_EOL)
+
+ Real left_coord = left_bound->relative_coordinate (common, X_AXIS);
+
+ for (SCM s = cols; gh_pair_p (s); s = ly_cdr (s))
{
- me->warning ("junking empty cluster");
- return SCM_EOL;
+ Grob * col = unsmob_grob (ly_car (s));
+ Slice s = Note_column::head_positions_interval (col);
+ Grob * h = Note_column::first_head (col);
+
+ Real x = h->relative_coordinate (common, X_AXIS) - left_coord;
+ bottom_points.push (Offset (x, s[DOWN] *0.5));
+ top_points.push (Offset (x, s[UP] * 0.5));
}
- for (;
- columns_scm != SCM_EOL;
- columns_scm = ly_cdr (columns_scm)) {
- column_scm = ly_car (columns_scm);
- SCM col_scm = ly_car (column_scm);
- if (gh_number_p (col_scm))
- // broken spanner: this column not in this piece
- if (!column)
- continue; // still have to expect columns
- else
- break; // ok, we have seen all columns
- column = unsmob_grob (col_scm);
- column_scm = ly_cdr (column_scm);
- Real y_bottom = gh_scm2double (ly_car (column_scm));
- column_scm = ly_cdr (column_scm);
- Real y_top = gh_scm2double (ly_car (column_scm));
- Real x = column->relative_coordinate (common, X_AXIS);
- if (right_broken)
- x -= left_bound->relative_coordinate (common, X_AXIS);
- bottom_points.push (Offset (x, y_bottom));
- top_points.push (Offset (x, y_top));
- }
- if (right_broken)
+ /*
+ Across a line break we anticipate on the next pitches.
+ */
+ if (spanner->original_)
{
- Real y_bottom = gh_scm2double (ly_car (column_scm));
- column_scm = ly_cdr (column_scm);
- Real y_top = gh_scm2double (ly_car (column_scm));
- column_scm = ly_cdr (column_scm);
- Real x =
- right_bound->relative_coordinate (common, X_AXIS) -
- left_bound->relative_coordinate (common, X_AXIS);
- bottom_points.push (Offset (x, y_bottom));
- top_points.push (Offset (x, y_top));
+ Spanner *orig = dynamic_cast<Spanner*> (spanner->original_);
+
+ if (spanner->break_index_ < orig->broken_intos_.size()-1)
+ {
+ Spanner * next = orig->broken_intos_[spanner->break_index_+1];
+ SCM cols = next->get_grob_property ("columns");
+ if (gh_pair_p (cols))
+ {
+ Grob * col = unsmob_grob (ly_car (scm_last_pair (cols)));
+ Slice s = Note_column::head_positions_interval (col);
+ Real x = right_bound->relative_coordinate (common,X_AXIS) - left_coord;
+
+ bottom_points.insert (Offset (x, s[DOWN] * 0.5),0);
+ top_points.insert (Offset (x, s[UP] * 0.5),0);
+ }
+ }
}
+
+ bottom_points.reverse ();
+ top_points.reverse ();
+
Molecule out = brew_cluster_piece (me, bottom_points, top_points);
return out.smobbed_copy ();
}
ADD_INTERFACE (Cluster,"cluster-interface",
"A graphically drawn musical cluster.",
- "shape padding segments");
+ "shape padding columns");
get_daddy_grav ()->announce_grob (inf);
}
+/*
+ CAUSE is the object (typically a Music object) that
+ was the reason for making E.
+ */
void
Engraver::announce_grob (Grob* e, SCM cause)
{
ADD_INTERFACE (Stem,"stem-interface",
"A stem",
- "up-to-staff avoid-note-head adjust-if-on-staffline thickness stem-info beamed-lengths beamed-minimum-free-lengths beamed-extreme-minimum-free-lengths lengths beam stem-shorten duration-log beaming neutral-direction stem-end-position support-head note-heads direction length flag-style no-stem-extend stroke-style");
+ "french-beaming up-to-staff avoid-note-head adjust-if-on-staffline thickness stem-info beamed-lengths beamed-minimum-free-lengths beamed-extreme-minimum-free-lengths lengths beam stem-shorten duration-log beaming neutral-direction stem-end-position support-head note-heads direction length flag-style no-stem-extend stroke-style");
\consists "Thread_devnull_engraver"
\consists "Note_heads_engraver"
\consists "Rest_engraver"
+
+ % why here ?
\consists "Note_head_line_engraver"
\consists "Output_property_engraver"
TODO: revise typing.")
(grob-property-description 'self-alignment-Y number? "like self-alignment-X but for Y axis.")
-(grob-property-description 'segments list? "DOCME. ")
(grob-property-description 'semivocalis boolean? "is this neume a lisquescending one?.")
(grob-property-description 'shape symbol? "shape of cluster segments. Valid values include 'leftsided-stairs', 'rightsided-stairs', 'centered-stairs', and 'ramp'.")
(grob-property-description 'shorten number? "the amount of space that a stem should be shortened (DOCME!)")
(ClusterEvent
. (
(description . "Begins or ends a cluster.")
-
(internal-class-name . "Event")
- (types . (general-music cluster-event event))
+ (types . (general-music cluster-event span-event event))
))
(ContextSpeccedMusic
. (