From bff637281b422e87a600d30587beb3bd8314e7a3 Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Mon, 2 Feb 2004 10:47:23 +0000 Subject: [PATCH] * 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. --- ChangeLog | 16 +++ Documentation/topdocs/NEWS.texi | 3 + Documentation/user/invoking.itexi | 3 +- Documentation/user/refman.itely | 16 ++- VERSION | 2 +- input/regression/lyric-combine-new.ly | 6 +- input/test/lyrics-skip-notes.ly | 23 ++++ lily/hyphen-engraver.cc | 127 +++++++++++++---------- lily/new-lyric-combine-music-iterator.cc | 4 +- lily/parser.yy | 18 ++-- scm/define-grobs.scm | 3 +- scm/new-markup.scm | 120 +++++++++++++++++++++ 12 files changed, 264 insertions(+), 77 deletions(-) create mode 100644 input/test/lyrics-skip-notes.ly diff --git a/ChangeLog b/ChangeLog index 0e12fe0879..44877335ec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2004-02-02 Han-Wen Nienhuys + + * 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 * scripts/lilypond.py (ly_paper_to_latexpaper): Add newline before @@ -180,6 +194,8 @@ 2004-01-26 Han-Wen Nienhuys + * VERSION: release 2.1.15 + * lily/lyric-phrasing-engraver.cc (stop_translation_timestep): align all stanza numbers. diff --git a/Documentation/topdocs/NEWS.texi b/Documentation/topdocs/NEWS.texi index 8207622508..f5cc974212 100644 --- a/Documentation/topdocs/NEWS.texi +++ b/Documentation/topdocs/NEWS.texi @@ -17,6 +17,9 @@ Version 2.1.13 @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 diff --git a/Documentation/user/invoking.itexi b/Documentation/user/invoking.itexi index 2f9424b47a..72ca9ddaa2 100644 --- a/Documentation/user/invoking.itexi +++ b/Documentation/user/invoking.itexi @@ -132,7 +132,8 @@ to generate titling; an example demonstrating all these fields is in @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 diff --git a/Documentation/user/refman.itely b/Documentation/user/refman.itely index 88f621bd4e..a806975515 100644 --- a/Documentation/user/refman.itely +++ b/Documentation/user/refman.itely @@ -3536,15 +3536,16 @@ A complete example of a SATB score setup is in the file @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 @@ -3607,12 +3608,17 @@ prevent @code{LyricsVoice.stanza} being interpreted as a single 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 @@ -3634,6 +3640,8 @@ making or a music identifier @code{\foo} containing the syllable @end example + + @node Ambitus @subsection Ambitus @cindex ambitus diff --git a/VERSION b/VERSION index c0480ca46d..c26ba763d5 100644 --- a/VERSION +++ b/VERSION @@ -2,5 +2,5 @@ PACKAGE_NAME=LilyPond MAJOR_VERSION=2 MINOR_VERSION=1 PATCH_LEVEL=16 -MY_PATCH_LEVEL= +MY_PATCH_LEVEL=hwn1 diff --git a/input/regression/lyric-combine-new.ly b/input/regression/lyric-combine-new.ly index fffacd9c7d..41a9ccfe6e 100644 --- a/input/regression/lyric-combine-new.ly +++ b/input/regression/lyric-combine-new.ly @@ -1,9 +1,9 @@ \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." } diff --git a/input/test/lyrics-skip-notes.ly b/input/test/lyrics-skip-notes.ly new file mode 100644 index 0000000000..4673ea52b6 --- /dev/null +++ b/input/test/lyrics-skip-notes.ly @@ -0,0 +1,23 @@ + +\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 } + >> +} diff --git a/lily/hyphen-engraver.cc b/lily/hyphen-engraver.cc index 8e14ca48e3..fb83dc407f 100644 --- a/lily/hyphen-engraver.cc +++ b/lily/hyphen-engraver.cc @@ -2,32 +2,22 @@ hyphen-engraver.cc -- implement Hyphen_engraver source file of the GNU LilyPond music typesetter - - (c) 1999--2003 Glen Prideaux + + (c) 1999--2003 Glen Prideaux , + Han-Wen Nienhuys , + Jan Nieuwenhuizen */ -#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); @@ -36,33 +26,33 @@ protected: 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 (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); } } @@ -70,38 +60,61 @@ Hyphen_engraver::acknowledge_grob (Grob_info i) 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 (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()); } } @@ -109,21 +122,29 @@ Hyphen_engraver::process_acknowledged_grobs () 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", diff --git a/lily/new-lyric-combine-music-iterator.cc b/lily/new-lyric-combine-music-iterator.cc index b5d0729108..1e8356d6dd 100644 --- a/lily/new-lyric-combine-music-iterator.cc +++ b/lily/new-lyric-combine-music-iterator.cc @@ -71,6 +71,7 @@ New_lyric_combine_music_iterator::start_new_syllable () if (!b) return false; + /* FIXME: this is wrong use of construct_children () */ if (!lyrics_context_) construct_children (); @@ -135,7 +136,7 @@ Translator_group * 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; @@ -147,7 +148,6 @@ find_context_below (Translator_group * where, { Translator_group * tr = dynamic_cast (unsmob_translator (gh_car (s))); - found = find_context_below (tr, type, id); } diff --git a/lily/parser.yy b/lily/parser.yy index c22c66a425..72d4de1ed3 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -390,7 +390,6 @@ yylex (YYSTYPE *s, void * v) %type shorthand_command_req %type post_event tagged_post_event %type command_req verbose_command_req -%type hyphen_req %type string_number_event %type string bare_number number_expression number_term number_factor %type score_block score_body @@ -1425,10 +1424,7 @@ command_req: ; shorthand_command_req: - hyphen_req { - $$ = $1; - } - | BREATHE { + BREATHE { $$ = MY_MAKE_MUSIC("BreathingSignEvent"); } | E_TILDE { @@ -1499,6 +1495,11 @@ post_event: 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")); @@ -1664,13 +1665,6 @@ pitch_also_in_chords: | 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: '(' { diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index 6d83c4278f..3f2340989d 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -21,6 +21,7 @@ (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) @@ -28,7 +29,7 @@ ;; 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)))) )) diff --git a/scm/new-markup.scm b/scm/new-markup.scm index 06356aa985..4aa774a692 100644 --- a/scm/new-markup.scm +++ b/scm/new-markup.scm @@ -82,6 +82,126 @@ against SIGNATURE, reporting MAKE-NAME as the user-invoked function. 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. -- 2.39.2