new node.
* lily/grace-iterator.cc (process): descend to child for \grace.
* lily/timing-translator.cc (initialize): Timing_translator adds
Timing alias by itself.
* lily/context.cc (add_alias): new function.
* scm/lily.scm (tex-output-expression): new function, eval within
drawing API. Guards against eval vulnerabilities.
2004-03-18 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ * Documentation/user/changing-defaults.itely (Creating contexts):
+ new node.
+
+ * lily/grace-iterator.cc (process): descend to child for \grace.
+
+ * lily/timing-translator.cc (initialize): Timing_translator adds
+ Timing alias by itself.
+
+ * lily/context.cc (add_alias): new function.
+
* scm/lily.scm (tex-output-expression): new function, eval within
drawing API. Guards against eval vulnerabilities.
@unnumbered New features in 2.1 since 2.0
@itemize @bullet
+
+@item The @code{Timing_engraver} now sets the @code{Timing} alias on
+its containing context automatically.
+
@item The code for font selection has been rewritten. In addition to
existing font selection properties, the property @code{font-encoding}
-has been added, which makes the switch between normal @code{text} and other
-encodings like @code{braces}, @code{music} and @code{math}.
+has been added, which makes the switch between normal @code{text} and
+other encodings like @code{braces}, @code{music} and @code{math}.
@item The pmx2ly script has been removed from the distribution.
This information can be present on several levels. For example, the
effect of an accidental is limited to a single stave, while a bar line
must be synchronized across the entire score. To match this
-hierarchy, LilyPond's interpretation step is hierarchical. Properties
-are maintained `interpretation contexts', like Voice, Staff and Score,
-and each context can have different @emph{properties}, variables that
-are contained in a context.
+hierarchy, LilyPond's interpretation step is hierarchical. There are
+interpretation contexts, like @context{Voice}, Staff and Score, and each level
+can maintain its own properties.
+
+Full description of all available contexts is in the program
+reference, see
+@ifhtml
+@internalsref{Contexts}
+@end ifhtml.
+@ifnothtml
+Translation @arrow{} Context.
+@end ifnothtml
@menu
+* Creating contexts::
* Changing context properties on the fly ::
-* context property defaults ::
+* Modifying context plug-ins::
+* Defining context defaults ::
* which properties to change::
@end menu
+@node Creating contexts
+@subsection Creating contexts
+
+For simple scores, the correct contexts are created automatically. For
+more complex scores, it is necessary to instantiate them by hand.
+There are three commands to do this.
+
+The easiest command is @code{\new}, and it also the quickest to type.
+It is prepended to a music expression, for example
+
+@example
+ \new @var{type} @var{music expression}
+@end example
+
+@noindent
+where @var{type} is a context name (like @code{Staff} or
+@code{Voice}). This command creates a new context, and starts
+interpreting @var{music expression} with that.
+
+A practical application of @code{\new} is a score with many
+staves. Each part that should be on its own staff, gets a @code{\new
+Staff}.
+
+@lilypond[verbatim,relative=2,raggedright]
+ << \new Staff { c4 c }
+ \new Staff { d4 d }
+ >>
+@end lilypond
+
+
+The @code{\context} command also directs a music expression to a
+context object, but gives the context an extra name. The syntax is
+
+@example
+ \context @var{type} = @var{id} @var{music}
+@end example
+
+This form will search for an existing context of type @var{type}
+called @var{id}. If that context does not exist yet, it is created.
+This is useful if the context referred to later on. For example, when
+setting lyrics the melody is in a named context
+
+@example
+ \context Voice = "@b{tenor}" @var{music}
+@end example
+
+@noindent
+so the texts can be properly aligned to its notes,
+
+@example
+\new Lyrics \lyricsto "@b{tenor}" @var{lyrics}
+@end example
+
+@noindent
+
+Another possibility is funneling two different music expressions into
+one context. In the following example, articulations and notes are
+entered separately,
+
+@example
+music = \notes { c4 c4 }
+arts = \notes { s4-. s4-> }
+@end example
+
+They are combined by sending both to the same @context{Voice} context,
+
+@example
+ << \new Staff \context Voice = "A" \music
+ \context Voice = "A" \arts
+ >>
+@end example
+@lilypond[raggedright]
+music = \notes \context Voice = "one" { c4 c4 }
+arts = \notes \context Voice = "one" { s4-. s4-> }
+\score {
+ << \new Staff \context Voice = "A" \music
+ \context Voice = "A" \arts
+ >>
+}
+@end lilypond
+
+
+
+The third command for creating contexts is
+@example
+ \context @var{type} @var{music}
+@end example
+
+
+@noindent
+It is similar to @code{\context} with @code{= @var{id}}, but now it
+matches any context of type @var{type}, regardless of its given name.
+
+This variant is used with music expressions that can be interpreted at
+several levels. For example, the @code{\applyoutput} command (see
+@ref{Running a function on all layout objects}). Without an explicit
+@code{\context}, it is usually is applied to @context{Voice}
+
+@example
+ \applyoutput #@var{function} % apply to Voice
+@end example
+
+To have it interpreted at @context{Score} or @context{Staff} level use
+these forms
+
+@example
+ \context Score \applyoutput #@var{function}
+ \context Staff \applyoutput #@var{function}
+@end example
+
+
@node Changing context properties on the fly
@subsection Changing context properties on the fly
-Context variables, properties, can be changed during the
-interpretation step. This is achieved by inserting the @code{\set}
-command in the music,
+Each context can have different @emph{properties}, variables contained
+in that context. They can be changed during the interpretation step.
+This is achieved by inserting the @code{\set} command in the music,
@quotation
@code{\set }[@var{context}]@code{.}@var{prop}@code{ = #}@var{value}
this case, it is @code{#t}, the boolean True value.
If the @var{context} argument is left out, then the current
-bottom-most context (typically ChordNames, Voice or Lyrics) is used.
+bottom-most context (typically ChordNames, @context{Voice} or Lyrics) is used.
In this example,
@lilypond[verbatim,relative=2]
@noindent
which removes the definition of @var{prop}. This command only removes
-definitions set in
-@var{context}. in
+the definition if it is set in @var{context}. In
@example
- \set staff.autoBeaming = ##f
- \unset voice.autoBeaming
+ \set Staff.autoBeaming = ##f
+ \unset Voice.autoBeaming
@end example
@noindent
the current voice does not have the property, and the definition at
staff level remains intact.
-Settings that should only apply to a single time-step can be entered
-easily with @code{\once}, for example in
+Settings that should only apply to a single time-step can be entered
+easily with @code{\once}, for example in
@lilypond[verbatim,relative=2]
c4
@code{fontSize} is unset after the third note.
+A full description of all available context properties is in the
+program reference, see
+@ifhtml
+@internalsref{Tunable-context-properties}.
+@end ifhtml
+@ifnothtml
+Translation @arrow{} Tunable context properties.
+@end ifnothtml
+
+
@node Modifying context plug-ins
@subsection Modifying context plug-ins
+Notation contexts (like Score and Staff) not only store properties,
+they also contain plug-ins, called ``engravers'' that create notation
+elements. For example, the Voice context contains a
+@code{Note_head_engraver} and the Staff context contains a
+@code{Key_signature_engraver}.
+
+For a full a description of each plug-in, see
+@ifhtml
+@internalsref{Engravers}
+@end ifhtml
+@ifnothtml
+Program reference @arrow Translation @arrow{} Engravers.
+@end ifnothtml
+Every context described in
+@ifhtml
+@internalsref{Contexts}
+@end ifhtml.
+@ifnothtml
+Program reference @arrow Translation @arrow{} Context.
+@end ifnothtml
+lists the engravers used for that context.
+
+
+It can be useful to shuffle around these plug-ins. This is done by
+starting a new context, with @code{\new} or @code{\context}, and
+modifying it like this,
+
+@example
+ \new @var{context} \with @{
+ \consists @dots{}
+ \consists @dots{}
+ \remove @dots{}
+ \remove @dots{}
+ @emph{etc.}
+ @}
+ @var{..music..}
+@end example
+
+where the @dots{} should be the name of an engraver. Here is a simple
+example which removes @code{Time_signature_engraver} and
+@code{Clef_engraver} from a @code{Staff} context,
+
+@lilypond[relative=1, verbatim]
+<< \new Staff {
+ f2 g
+ }
+ \new Staff \with {
+ \remove Time_signature_engraver
+ \remove Clef_engraver
+ } {
+ f2 g2
+ }
+>>
+@end example
+
+In the second stave there are no time signature or clef symbols. This
+is a rather crude method of making objects disappear, it will affect
+the entire staff. More sophisticated method is shown in TODO.
+
+The next example shows a practical application. Bar lines and time
+signatures are normally synchronized across the score. This is done
+by the @code{Timing_engraver}. This plug-in keeps an administration of
+time signature, location within the measure, etc. By moving the
+@code{Timing_engraver} engraver from Score to Staff context, we can
+have score where each staff has its own time signature.
+
+@cindex polymetric scores
+
+
+@lilypond[relative=1,raggedright,verbatim]
+\new Score \with {
+ \remove Timing_engraver
+} <<
+ \new Staff \with {
+ \consists Timing_engraver
+ } {
+ \time 3/4
+ c4 c c c c c
+ }
+ \new Staff \with {
+ \consists Timing_engraver {
+ } {
+ \time 2/4
+ c4 c c c c c
+ }
+ >>
+@end lilypond
@node Defining context defaults
@end macro
@end iftex
+@macro arrow{}
+@iftex
+@tex $\\Rightarrow$ @end tex@c
+@end iftex
+@ifhtml
+@html
+→
+@end html
+@end ifhtml
+@ifinfo
+-->
+@end ifinfo
+@end macro
+
+
@iftex
@end macro
+@ifhtml
+@macro context{NAME}
+@code{NAME}@c should use internalsref
+@cindex \NAME\@c
+@end macro
+
+
+
@c
@c ARGGGHHHHH! I want
@cindex @code{\WHAT\}
@code{\WHAT\},
@end macro
-
-@macro syntax
-@noindent
-@subsubheading Syntax
-
-@end macro
-
@c @evenheading @thispage @| @|
@c @oddheading @| @| @thispage @|
-@macro ar{}
-@iftex
-@tex $\\Rightarrow$ @end tex@c
-@end iftex
-@ifhtml
-@html
-→
-@end html
-@end ifhtml
-@ifinfo
--->
-@end ifinfo
-@end macro
+@include macros.itexi
+
@ignore
We do not use refs for Info:
@c arrowref
@macro aref{word}
@iftex
-@w{@ar{}@strong{\word\}}@c
+@w{@arrow{}@strong{\word\}}@c
@end iftex
@ifhtml
@ar{}@ref{\word\, @strong{\word\}}@c
@refbugs
-If you do a nested repeat like
+A nested repeat like
@example
\repeat @dots{}
@end example
@noindent
-then it is ambiguous to which @code{\repeat} the @code{\alternative}
-belongs. This ambiguity is resolved by always having the
-@code{\alternative} belong to the inner @code{\repeat}. For clarity,
-it is advisable to use braces in such situations.
+is ambiguous, since it is is not clear to which @code{\repeat} the
+@code{\alternative} belongs. This ambiguity is resolved by always
+having the @code{\alternative} belong to the inner @code{\repeat}.
+For clarity, it is advisable to use braces in such situations.
@cindex ambiguity
@node Repeats and MIDI
-\version "2.1.30"
+\version "2.1.31"
\header{ texidoc="@cindex Time Signature Multiple
\context{
\StaffContext
\consists "Timing_engraver"
- \alias "Timing"
+
}
}
}
SCM axes = me->get_property ("axes");
if (!gh_pair_p (axes)
- || scm_memq (sa1, axes) == SCM_BOOL_F
- || scm_memq (sa2, axes) == SCM_BOOL_F)
+ || scm_c_memq (sa1, axes) == SCM_BOOL_F
+ || scm_c_memq (sa2, axes) == SCM_BOOL_F)
{
SCM ax = gh_cons (sa1, SCM_EOL);
if (a1 != a2)
for ( SCM s = gh_car (right_beaming); gh_pair_p (s); s = gh_cdr (s))
{
int k = - right_dir * gh_scm2int (gh_car (s)) + i;
- if (scm_memq (scm_int2num (k), left_beaming) != SCM_BOOL_F)
+ if (scm_c_memq (scm_int2num (k), left_beaming) != SCM_BOOL_F)
count ++;
}
gh_pair_p (s); s =gh_cdr (s))
{
int b = gh_scm2int (gh_car (s));
- if (scm_memq (gh_car (s), right) != SCM_BOOL_F)
+ if (scm_c_memq (gh_car (s), right) != SCM_BOOL_F)
{
full_beams.push (b);
}
gh_pair_p (s); s =gh_cdr (s))
{
int b = gh_scm2int (gh_car (s));
- if (scm_memq (gh_car (s), left) == SCM_BOOL_F)
+ if (scm_c_memq (gh_car (s), left) == SCM_BOOL_F)
{
rfliebertjes.push (b);
}
for ( SCM s = gh_car (beaming); gh_pair_p (s) ; s = gh_cdr (s))
{
- if (scm_memq (gh_car (s), gh_cdr (beaming)) != SCM_BOOL_F)
+ if (scm_c_memq (gh_car (s), gh_cdr (beaming)) != SCM_BOOL_F)
l.add_point (gh_scm2int (gh_car (s)));
}
else
tg = new Context ();
-
tg->definition_ = self_scm ();
SCM trans_names = get_translator_names (ops);
g->simple_trans_list_ = names_to_translators (trans_names, tg);
tg->implementation_ = g->self_scm ();
g->daddy_context_ = tg;
+ tg->aliases_ = context_aliases_ ;
scm_gc_unprotect_object (g->self_scm ());
return l;
}
-bool
-Context_def::is_alias (SCM sym) const
-{
- bool b = sym == context_name_;
-
- for (SCM a = context_aliases_; !b && gh_pair_p (a); a = ly_cdr (a))
- b = b || sym == ly_car (a);
-
- return b;
-}
{
daddy_context_ = 0;
init_ = false;
+ aliases_ = SCM_EOL;
iterator_count_ = 0;
implementation_ = SCM_EOL;
properties_scm_ = SCM_EOL;
if (sym == ly_symbol2scm ("Bottom")
&& !gh_pair_p (accepts_list_))
return true;
- return unsmob_context_def (definition_)->is_alias (sym);
+ if (sym == unsmob_context_def (definition_)->get_context_name ())
+ return true;
+
+ return scm_c_memq (sym, aliases_) != SCM_BOOL_F;
+}
+
+void
+Context::add_alias (SCM sym)
+{
+ aliases_ = scm_cons (sym, aliases_);
}
+
+
void
Context::internal_set_property (SCM sym, SCM val)
{
Context * me = (Context*) SCM_CELL_WORD_1 (sm);
scm_gc_mark (me->context_list_);
+ scm_gc_mark (me->aliases_);
scm_gc_mark (me->definition_);
scm_gc_mark (me->properties_scm_);
scm_gc_mark (me->accepts_list_);
SCM ack_ifs = scm_assoc (ly_symbol2scm ("interfaces-acked"), tr->translator_description ());
ack_ifs = gh_cdr (ack_ifs);
for (SCM s = ifaces; ly_pair_p (s); s = ly_cdr (s))
- if (scm_memq (ly_car (s), ack_ifs) != SCM_BOOL_F)
+ if (scm_c_memq (ly_car (s), ack_ifs) != SCM_BOOL_F)
return true;
return false;
}
Moment main ;
main.main_part_ = - start_mom_.grace_part_ + m.grace_part_;
Music_wrapper_iterator::process (main);
+
+ /*
+ We can safely do this, since \grace should always be inside
+ sequential.
+ */
+ descend_to_child (child_iter_->get_outlet ());
}
Moment
continue;
}
- found= found || (scm_memq (sym, gh_caddr (iface)) != SCM_BOOL_F);
+ found= found || (scm_c_memq (sym, gh_caddr (iface)) != SCM_BOOL_F);
}
if (!found)
bool
Grob::has_offset_callback (SCM cb, Axis a)const
{
- return scm_memq (cb, dim_cache_[a].offset_callbacks_) != SCM_BOOL_F;
+ return scm_c_memq (cb, dim_cache_[a].offset_callbacks_) != SCM_BOOL_F;
}
void
{
SCM ifs = get_property ("interfaces");
- return scm_memq (k, ifs) != SCM_BOOL_F;
+ return scm_c_memq (k, ifs) != SCM_BOOL_F;
}
Context * instantiate (SCM extra_ops);
SCM to_alist () const;
- bool is_alias (SCM) const;
static SCM make_scm () ;
SCM clone_scm ()const;
SCM properties_scm_;
SCM context_list_;
SCM accepts_list_;
+ SCM aliases_;
+
Context * daddy_context_;
Context ();
virtual Score_context * get_score_context () const;
bool is_alias (SCM) const;
+ void add_alias (SCM);
void add_context (Context *trans);
bool is_bottom_context () const;
bool is_removable () const;
Music * get_music () const;
protected:
virtual void do_quit();
+ void descend_to_child (Context*);
private:
Interpretation_context_handle handle_;
Music * music_;
{
return false;
}
+
+/*
+ move to context of child iterator if it is deeper down in the
+ hierarchy.
+ */
+void
+Music_iterator::descend_to_child (Context * child_report)
+{
+ Context * me_report = get_outlet ();
+
+ Context * c = child_report;
+ while (c && c != me_report)
+ {
+ c = c->daddy_context_;
+ }
+
+ if (c == me_report)
+ set_translator (child_report);
+}
{
SCM ifs = get_property ("types");
- return scm_memq (k, ifs) != SCM_BOOL_F;
+ return scm_c_memq (k, ifs) != SCM_BOOL_F;
}
String
fingerings_.sort (&Finger_tuple::compare);
SCM orientations = get_property ("fingeringOrientations");
- bool up_p = scm_memq (ly_symbol2scm ("up"), orientations) != SCM_BOOL_F;
- bool down_p = scm_memq (ly_symbol2scm ("down"), orientations) != SCM_BOOL_F;
- bool left_p = scm_memq (ly_symbol2scm ("left"), orientations) != SCM_BOOL_F;
- bool right_p = scm_memq (ly_symbol2scm ("right"), orientations) != SCM_BOOL_F;
+ bool up_p = scm_c_memq (ly_symbol2scm ("up"), orientations) != SCM_BOOL_F;
+ bool down_p = scm_c_memq (ly_symbol2scm ("down"), orientations) != SCM_BOOL_F;
+ bool left_p = scm_c_memq (ly_symbol2scm ("left"), orientations) != SCM_BOOL_F;
+ bool right_p = scm_c_memq (ly_symbol2scm ("right"), orientations) != SCM_BOOL_F;
Direction hordir = (right_p) ? RIGHT : LEFT;
if (left_p || right_p)
{
iter_->ok () is tautology, but what the heck.
*/
if (iter_ && iter_->ok ())
- descend_to_child ();
+ descend_to_child (iter_->get_outlet ());
}
iter_ = 0;
}
-/*
- move to context of child iterator if it is deeper down in the
- hierarchy.
- */
-void
-Sequential_iterator::descend_to_child ()
-{
- Context * child_report = child_report = iter_->get_outlet ();
- Context * me_report = get_outlet ();
- Context * c = child_report;
- while (c && c != me_report)
- {
- c = c->daddy_context_;
- }
-
- if (c == me_report)
- set_translator (child_report);
-}
void
Sequential_iterator::process (Moment until)
if (iter_->ok ())
return ;
- descend_to_child ();
+ descend_to_child (iter_->get_outlet ());
next_element (true);
}
}
/* descr */ " Responsible for synchronizing timing information from staves. "
"Normally in @code{Score}. In order to create polyrhythmic music, "
"this engraver should be removed from @code{Score} and placed in "
-"@code{Staff}.",
+"@code{Staff}. "
+"\n\nThis engraver adds the alias @code{Timing} to its containing context."
+
+ ,
/* creats*/ "",
/* accepts */ "",
/* acks */ "",
/*
move this to engraver-init.ly?
*/
-
+ daddy_context_->add_alias (ly_symbol2scm ("Timing"));
daddy_context_->set_property ("timing" , SCM_BOOL_T);
daddy_context_->set_property ("currentBarNumber" , gh_int2scm (1));
else
{
measposp = now;
- daddy_context_->set_property ("measurePosition", measposp.smobbed_copy ());
+ daddy_context_->set_property ("measurePosition",
+ measposp.smobbed_copy ());
}
measposp += dt;
daddy_context_->set_property ("measurePosition", measposp.smobbed_copy ());
}
-ENTER_DESCRIPTION (Timing_translator,"","","","","","");
+ENTER_DESCRIPTION (Timing_translator,
+ "This engraver adds the alias "
+ "@code{Timing} to its containing context."
+ ,
+
+ "","","","","");
tr->translator_description ());
ack_ifs = gh_cdr (ack_ifs);
for (SCM s = ifaces; ly_pair_p (s); s = ly_cdr (s))
- if (scm_memq (ly_car (s), ack_ifs) != SCM_BOOL_F)
+ if (scm_c_memq (ly_car (s), ack_ifs) != SCM_BOOL_F)
return true;
return false;
}
% move the alias along with the engraver.
- %% TODO? add this alias from Timing_engraver::initialize() ?
\consists "Timing_engraver"
- \alias "Timing"
\consists "Output_property_engraver"
\consists "System_start_delimiter_engraver"
%% don't want to route anything out of here:
\alias "Staff"
- \alias "Timing"
\alias "Voice"
\consists "Swallow_engraver"
\description "Silently discards all musical information given to this context. "
;;; Library functions
-(if (defined? 'set-debug-cell-accesses!)
- (set-debug-cell-accesses! #t))
+;(if (defined? 'set-debug-cell-accesses!)
+; (set-debug-cell-accesses! #t))
+
(use-modules (ice-9 regex)
(ice-9 safe)
(oop goops)
ly:get-stencil-extent -> ly:stencil-extent
'''))
+def conv (str):
+ str = re.sub (r'\\alias\s*"?Timing"?', '', str)
+ return str
+
+conversions.append (((2,1,31), conv,
+ '''remove \\alias Timing'''))
+
################################
# END OF CONVERSIONS
################################