+2004-02-02 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+ * scm/new-markup.scm (markup): a macro that provides a
+ LilyPond-like syntax in scheme for building markups, in order to
+ help markup command definition. (Nicolas Sceaux)
+
+ * input/test/lyrics-skip-notes.ly: new example.
+
+ * lily/parser.yy (post_event): make HYPHEN into postfix event.
+
+ * lily/new-lyric-combine-music-iterator.cc (find_context_below):
+ use is_alias() iso. == . This fixes lyrics on
+ GregorianTranscriptions.
+
2004-02-02 Mats Bengtsson <mabe@drongo.s3.kth.se>
* scripts/lilypond.py (ly_paper_to_latexpaper): Add newline before
2004-01-26 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ * VERSION: release 2.1.15
+
* lily/lyric-phrasing-engraver.cc (stop_translation_timestep):
align all stanza numbers.
@end ignore
@itemize @bullet
+@item Voice names, for vocal lines, have been added. They are similar
+to instrument names. They can be set by defining @code{vocalName}
+and @code{vocNam}.
@item Safe mode has been reinstated for lilypond.
When lilypond is invoked with @code{--safe-mode}, @TeX{} and
@item footer
A text to print in the footer of all but the last page.
@item tagline
- Line to print at the bottom of last page. The default text is ``Engraved by LilyPond @var{version-number}''.
+ Line to print at the bottom of last page. The default text is ``Engraved
+by LilyPond @var{version-number}''.
@end table
@seealso
-Internals: @internalsref{LyricCombineMusic}, @internalsref{Lyrics},
-@internalsref{Melisma_engraver}.
+Internals: Music expressions: @internalsref{LyricCombineMusic},
+Contexts: @internalsref{LyricsVoice}, @internalsref{Melisma_engraver}.
Examples: @inputfileref{input/template,satb.ly},
@inputfileref{input/regression,lyric-combine-new.ly}.
@refbugs
-Melismata are not detected automatically, and must be inserted by hand.
+Melismata are not detected automatically, and extender lines must be
+inserted by hand.
@node More stanzas
string.
Names of the singers should be added using @code{LyricsVoice
-. instrument} and @code{LyricsVoice . instr}, analogous to instrument
+. vocalName} and @code{LyricsVoice . vocNam}, analogous to instrument
annotations for staves.
To make empty spaces in lyrics, use @code{\skip}.
+@seealso
+
+Internals: Layout objects @internalsref{LyricText}
+@internalsref{VocalName}. Music expressions:
+@internalsref{LyricEvent}.
@refbugs
@end example
+
+
@node Ambitus
@subsection Ambitus
@cindex ambitus
MAJOR_VERSION=2
MINOR_VERSION=1
PATCH_LEVEL=16
-MY_PATCH_LEVEL=
+MY_PATCH_LEVEL=hwn1
\version "2.1.10"
\header {
- texidoc = "With the newaddlyrics mechanism, individual lyric lines
- can be associated with one melody line. For each lyric line, can
- be tuned whether to follow melismata or not."
+ texidoc = "With the @code{\\lyricsto} mechanism, individual lyric
+ lines can be associated with one melody line. For each lyric line,
+ can be tuned whether to follow melismata or not."
}
--- /dev/null
+
+\header
+{
+texidoc ="
+
+By inserting @code{\\skip} statements into lyric lines, one can put less lyric syllables to a melody.
+
+"
+}
+
+
+% shorthand for Skip Lyric
+sl = \notes { \skip 4 }
+
+\version "2.1.16"
+\score {
+ <<
+ \context Voice = "A" \notes {c4 c c c}
+ \lyricsto "A" \context LyricsVoice=A \lyrics { foo __ \sl \sl bar }
+ \lyricsto "A" \context LyricsVoice=B \lyrics { foo -- \sl baz bar }
+ \lyricsto "A" \context LyricsVoice=C \lyrics { foo -- baz -- baaz bar }
+ >>
+}
hyphen-engraver.cc -- implement Hyphen_engraver
source file of the GNU LilyPond music typesetter
-
- (c) 1999--2003 Glen Prideaux <glenprideaux@iname.com>
+
+ (c) 1999--2003 Glen Prideaux <glenprideaux@iname.com>,
+ Han-Wen Nienhuys <hanwen@cs.uu.nl>,
+ Jan Nieuwenhuizen <janneke@gnu.org>
*/
-#include "flower-proto.hh"
-#include "event.hh"
+#include "warn.hh"
#include "hyphen-spanner.hh"
-#include "paper-column.hh"
#include "item.hh"
#include "engraver.hh"
-/**
- Generate an centred hyphen. Should make a Hyphen_spanner that
- typesets a nice centred hyphen of varying length depending on the
- gap between syllables.
-
- We remember the last Item that come across. When we get a
- event, we create the spanner, and attach the left point to the
- last lyrics, and the right point to any lyrics we receive by
- then. */
class Hyphen_engraver : public Engraver
{
- Grob *last_lyric_;
- Grob *current_lyric_;
- Music* req_;
+ Music* ev_;
Spanner* hyphen_;
+ Spanner * finished_hyphen_;
public:
TRANSLATOR_DECLARATIONS(Hyphen_engraver);
virtual void finalize ();
virtual bool try_music (Music*);
virtual void stop_translation_timestep ();
- virtual void process_acknowledged_grobs ();
+ virtual void process_music ();
private:
};
+
Hyphen_engraver::Hyphen_engraver ()
{
- current_lyric_ = 0;
- last_lyric_ = 0;
hyphen_ = 0;
- req_ = 0;
+ finished_hyphen_ = 0;
+ ev_ = 0;
}
void
Hyphen_engraver::acknowledge_grob (Grob_info i)
{
- // -> text-item
- if (i.grob_->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface")))
+ Item * item = dynamic_cast<Item*> (i.grob_);
+ // -> text_item
+ if (item && item->internal_has_interface (ly_symbol2scm ("lyric-syllable-interface")))
{
- current_lyric_ = i.grob_;
- if (hyphen_
- && !hyphen_->get_bound (RIGHT))
- {
- hyphen_->set_bound (RIGHT, i.grob_);
- }
+ if (hyphen_)
+ hyphen_->set_bound (LEFT, item);
+
+ if (finished_hyphen_)
+ finished_hyphen_->set_bound (RIGHT, item);
}
}
bool
Hyphen_engraver::try_music (Music* r)
{
- if (req_)
- return false;
+ if (ev_)
+ return false;
- req_ = r;
- return true;
+ ev_ = r;
+ return true;
+}
+
+void
+completize_hyphen (Spanner* sp)
+{
+ if (!sp->get_bound (RIGHT))
+ {
+ SCM heads = sp->get_grob_property ("heads");
+ if (gh_pair_p (heads))
+ {
+ Item* it = dynamic_cast<Item*> (unsmob_grob (gh_car (heads)));
+ if (it)
+ sp->set_bound (RIGHT, it);
+ }
+ }
}
+
+
void
Hyphen_engraver::finalize ()
{
if (hyphen_)
{
- req_->origin ()->warning (_ ("unterminated hyphen"));
- hyphen_->set_bound (RIGHT, unsmob_grob (get_property ("currentCommandColumn")));
+ completize_hyphen (hyphen_);
+
+ if (!hyphen_->get_bound (RIGHT))
+ hyphen_->warning (_ ("unterminated hyphen"));
+ typeset_grob (hyphen_);
+ hyphen_ = 0;
+ }
+
+ if (finished_hyphen_)
+ {
+ completize_hyphen (finished_hyphen_);
+
+ if (!finished_hyphen_->get_bound (RIGHT))
+ finished_hyphen_->warning (_("unterminated hyphen"));
+ typeset_grob (finished_hyphen_);
+ finished_hyphen_ =0;
}
}
void
-Hyphen_engraver::process_acknowledged_grobs ()
+Hyphen_engraver::process_music ()
{
- if (req_ &&! hyphen_)
+ if (ev_)
{
- if (!last_lyric_)
- {
- req_->origin ()->warning (_ ("Nothing to connect hyphen to on the left. Ignoring hyphen event."));
- return;
- }
-
hyphen_ = make_spanner ("LyricHyphen");
-
- hyphen_->set_bound (LEFT, last_lyric_);
- announce_grob(hyphen_, req_->self_scm());
+ announce_grob (hyphen_, ev_->self_scm());
}
}
void
Hyphen_engraver::stop_translation_timestep ()
{
- if (hyphen_)
+ if (finished_hyphen_ && finished_hyphen_->get_bound (RIGHT))
{
- typeset_grob (hyphen_);
- hyphen_ = 0;
+ typeset_grob (finished_hyphen_);
+ finished_hyphen_ = 0;
}
- if (current_lyric_)
+ if (finished_hyphen_ && hyphen_)
{
- last_lyric_ = current_lyric_;
- current_lyric_ =0;
+ programming_error ("Haven't finished hyphen yet.");
+ typeset_grob (finished_hyphen_);
+ finished_hyphen_ =0;
}
- req_ = 0;
+
+ if (hyphen_)
+ finished_hyphen_ = hyphen_;
+ hyphen_ = 0;
+
+ ev_ = 0;
}
+
+
ENTER_DESCRIPTION(Hyphen_engraver,
/* descr */ "Create lyric hyphens",
/* creats*/ "LyricHyphen",
if (!b)
return false;
+ /* FIXME: this is wrong use of construct_children () */
if (!lyrics_context_)
construct_children ();
find_context_below (Translator_group * where,
String type, String id)
{
- if (where->context_name () == type)
+ if (where->is_alias (ly_symbol2scm (type.to_str0 ())))
{
if (id == "" || where->id_string_ == id)
return where;
{
Translator_group * tr = dynamic_cast<Translator_group*> (unsmob_translator (gh_car (s)));
-
found = find_context_below (tr, type, id);
}
%type <music> shorthand_command_req
%type <music> post_event tagged_post_event
%type <music> command_req verbose_command_req
-%type <music> hyphen_req
%type <music> string_number_event
%type <scm> string bare_number number_expression number_term number_factor
%type <score> score_block score_body
;
shorthand_command_req:
- hyphen_req {
- $$ = $1;
- }
- | BREATHE {
+ BREATHE {
$$ = MY_MAKE_MUSIC("BreathingSignEvent");
}
| E_TILDE {
direction_less_event {
$$ = $1;
}
+ | HYPHEN {
+ if (!THIS->lexer_->lyric_state_b ())
+ THIS->parser_error (_ ("Have to be in Lyric mode for lyrics"));
+ $$ = MY_MAKE_MUSIC("HyphenEvent");
+ }
| EXTENDER {
if (!THIS->lexer_->lyric_state_b ())
THIS->parser_error (_ ("Have to be in Lyric mode for lyrics"));
| steno_tonic_pitch
;
-hyphen_req:
- HYPHEN {
- if (!THIS->lexer_->lyric_state_b ())
- THIS->parser_error (_ ("Have to be in Lyric mode for lyrics"));
- $$ = MY_MAKE_MUSIC("HyphenEvent");
- }
- ;
close_event:
'(' {
(cautionary-style . parentheses)
(after-line-breaking-callback . ,Accidental_interface::after_line_breaking) (meta . ((interfaces . (item-interface accidental-interface font-interface))))
))
+
(AccidentalPlacement
. (
(X-extent-callback . ,Axis_group_interface::group_extent_callback)
;; this is quite small, but it is very ugly to have
;; accs closer to the previous note than to the next one.
- (right-padding . 0.2)
+ (right-padding . 0.25)
(meta . ((interfaces . (item-interface accidental-placement-interface))))
))
error-msg #f)
(cons markup-function args))))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; markup constructors
+;;; lilypond-like syntax for markup construction in scheme.
+
+(use-modules (ice-9 optargs)
+ (ice-9 receive))
+
+(defmacro*-public markup (#:rest body)
+ "The `markup' macro provides a lilypond-like syntax for building markups.
+
+ - #:COMMAND is used instead of \\COMMAND
+ - #:lines ( ... ) is used instead of { ... }
+ - #:center ( ... ) is used instead of \\center < ... >
+ - etc.
+
+Example:
+ \\markup { foo
+ \\raise #0.2 \\hbracket \\bold bar
+ \\override #'(baseline-skip . 4)
+ \\bracket \\column < baz bazr bla >
+ }
+ <==>
+ (markup \"foo\"
+ #:raise 0.2 #:hbracket #:bold \"bar\"
+ #:override '(baseline-skip . 4)
+ #:bracket #:column (\"baz\" \"bazr\" \"bla\"))
+Use `markup*' in a \\notes block."
+
+ (car (compile-all-markup-expressions `(#:line ,body))))
+
+(defmacro*-public markup* (#:rest body)
+ "Same as `markup', for use in a \\notes block."
+ `(ly:export (markup ,@body)))
+
+
+(define (compile-all-markup-expressions expr)
+ "Return a list of canonical markups expressions, eg:
+ (#:COMMAND1 arg11 arg12 #:COMMAND2 arg21 arg22 arg23)
+ ===>
+ ((make-COMMAND1-markup arg11 arg12)
+ (make-COMMAND2-markup arg21 arg22 arg23) ...)"
+ (do ((rest expr rest)
+ (markps '() markps))
+ ((null? rest) (reverse markps))
+ (receive (m r) (compile-markup-expression rest)
+ (set! markps (cons m markps))
+ (set! rest r))))
+
+(define (keyword->make-markup key)
+ "Transform a keyword, eg. #:COMMAND, in a make-COMMAND-markup symbol."
+ (string->symbol (string-append "make-" (symbol->string (keyword->symbol key)) "-markup")))
+
+(define (compile-markup-expression expr)
+ "Return two values: the first complete canonical markup expression found in `expr',
+eg (make-COMMAND-markup arg1 arg2 ...), and the rest expression."
+ (cond ((and (pair? expr)
+ (keyword? (car expr)))
+ ;; expr === (#:COMMAND arg1 ...)
+ (let* ((command (symbol->string (keyword->symbol (car expr))))
+ (sig (markup-command-signature (car (lookup-markup-command command))))
+ (sig-len (length sig)))
+ (do ((i 0 (1+ i))
+ (args '() args)
+ (rest (cdr expr) rest))
+ ((>= i sig-len)
+ (values (cons (keyword->make-markup (car expr)) (reverse args)) rest))
+ (cond ((eqv? (list-ref sig i) markup-list?)
+ ;; (car rest) is a markup list
+ (set! args (cons `(list ,@(compile-all-markup-expressions (car rest))) args))
+ (set! rest (cdr rest)))
+ (else
+ ;; pick up one arg in `rest'
+ (receive (a r) (compile-markup-arg rest)
+ (set! args (cons a args))
+ (set! rest r)))))))
+ ((and (pair? expr)
+ (pair? (car expr))
+ (keyword? (caar expr)))
+ ;; expr === ((#:COMMAND arg1 ...) ...)
+ (receive (m r) (compile-markup-expression (car expr))
+ (values m (cdr expr))))
+ (else
+ ;; expr === (symbol ...) or ("string" ...) or ((funcall ...) ...)
+ (values (car expr)
+ (cdr expr)))))
+
+(define (compile-all-markup-args expr)
+ "Transform `expr' into markup arguments"
+ (do ((rest expr rest)
+ (args '() args))
+ ((null? rest) (reverse args))
+ (receive (a r) (compile-markup-arg rest)
+ (set! args (cons a args))
+ (set! rest r))))
+
+(define (compile-markup-arg expr)
+ "Return two values: the desired markup argument, and the rest arguments"
+ (cond ((null? expr)
+ ;; no more args
+ (values '() '()))
+ ((keyword? (car expr))
+ ;; expr === (#:COMMAND ...)
+ ;; ==> build and return the whole markup expression
+ (compile-markup-expression expr))
+ ((and (pair? (car expr))
+ (keyword? (caar expr)))
+ ;; expr === ((#:COMMAND ...) ...)
+ ;; ==> build and return the whole markup expression(s)
+ ;; found in (car expr)
+ (receive (markup-expr rest-expr) (compile-markup-expression (car expr))
+ (if (null? rest-expr)
+ (values markup-expr (cdr expr))
+ (values `(list ,markup-expr ,@(compile-all-markup-args rest-expr))
+ (cdr expr)))))
+ ((and (pair? (car expr))
+ (pair? (caar expr)))
+ ;; expr === (((foo ...) ...) ...)
+ (values (cons 'list (compile-all-markup-args (car expr))) (cdr expr)))
+ (else (values (car expr) (cdr expr)))))
+
;;;;;;;;;;;;;;;
;;; Utilities for storing and accessing markup commands signature
;;; and keyword.