From 77d72a6b9e7e551dc4a3b365099f9fea339f9c72 Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Fri, 9 Dec 2005 23:58:55 +0000 Subject: [PATCH] * ly/engraver-init.ly (AncientRemoveEmptyStaffContext): remove Span_arpeggio_engraver, add Tweak_engraver to Score context. * lily/parser.yy: reorganize file layout. * ly/music-functions-init.ly: add tweak music function. * lily/grob-info.cc (ultimate_music_cause): new function: recursively lookup causes. * lily/parser.yy (chord_body_element): allow music functions for post-events, allow music functions for chord elements. * lily/font-config-scheme.cc (display_fontset): add cast. * python/convertrules.py (FatalConversionError.sub_syms): \tag #'(a b) -> \tag #'a \tag #'b rule. * python/musicexp.py (Output_printer.dump_version): new function --- ChangeLog | 34 +- Documentation/topdocs/NEWS.tely | 25 + Documentation/user/advanced-notation.itely | 7 +- THANKS | 5 +- input/regression/grob-tweak.ly | 22 + lily/auto-beam-engraver.cc | 2 +- lily/beam-engraver.cc | 79 +-- lily/font-config-scheme.cc | 2 +- lily/grob-info.cc | 15 +- lily/include/grob-info.hh | 3 +- lily/lily-lexer.cc | 1 - lily/note-head-line-engraver.cc | 1 + lily/parser.yy | 549 +++++++++++---------- lily/stem-engraver.cc | 2 +- lily/tweak-engraver.cc | 48 ++ ly/engraver-init.ly | 32 +- ly/music-functions-init.ly | 37 ++ python/convertrules.py | 13 + python/musicexp.py | 5 + scm/define-grobs.scm | 5 +- scm/define-music-properties.scm | 3 + 21 files changed, 563 insertions(+), 327 deletions(-) create mode 100644 input/regression/grob-tweak.ly create mode 100644 lily/tweak-engraver.cc diff --git a/ChangeLog b/ChangeLog index 82318adeb4..c89f366dac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,35 @@ -2005-12-09 Werner Lemberg +2005-12-10 Han-Wen Nienhuys - * mf/feta-beugel.mf (draw_brace): Use subpaths to assure correct - tension values. + * ly/engraver-init.ly (AncientRemoveEmptyStaffContext): remove + Span_arpeggio_engraver, add Tweak_engraver to Score context. + + * lily/parser.yy: reorganize file layout. + + * ly/music-functions-init.ly: add tweak music function. + + * lily/grob-info.cc (ultimate_music_cause): new function: + recursively lookup causes. + + * lily/parser.yy (chord_body_element): allow music functions for + post-events, allow music functions for chord elements. + + * lily/font-config-scheme.cc (display_fontset): add cast. + + * python/convertrules.py (FatalConversionError.sub_syms): \tag + #'(a b) -> \tag #'a \tag #'b rule. + + * python/musicexp.py (Output_printer.dump_version): new function + +2005-12-09 Han-Wen Nienhuys + + * lily/parser.yy (FIXME): remove \tag + (FIXME): remove tag_music() function. + + * lily/lily-lexer.cc: remove \tag + + * ly/music-functions-init.ly: define music-function "tag" + + * lily/parser.yy (chord_body_element): allow tags in chord bodies. 2005-12-08 Han-Wen Nienhuys diff --git a/Documentation/topdocs/NEWS.tely b/Documentation/topdocs/NEWS.tely index 6801d95811..b71f00ebce 100644 --- a/Documentation/topdocs/NEWS.tely +++ b/Documentation/topdocs/NEWS.tely @@ -45,6 +45,31 @@ This document is also available in @uref{NEWS.pdf,PDF}. @itemize @bullet +@item With the @code{\tweak} music function, layout objects that are directly +connected to input may be tuned, + +@lilypond[relative=2,fragment,raggedright] +< + \tweak #'font-size #3 c + \tweak #'color #red e + \tweak #'style #cross g + \tweak #'duration-log #1 a +>4 +@end lilypond + +This feature was sponsored by Sean Reed and Bertalan Fodor. + +@item Generic music functions may now also be used on articulations +and chord elements, eg. + +@verbatim + < \displayMusic c + e-\keepWithTag #'bla -\tag #'bla ^2 > +@end verbatim + +This feature was sponsored by Sean Reed and Bertalan Fodor. + + @item Spaces between lyrics and distance between syllables with hyphens may now be separately tuned through the @code{LyricSpace} grob. diff --git a/Documentation/user/advanced-notation.itely b/Documentation/user/advanced-notation.itely index 0433e25fad..a498d1f6d5 100644 --- a/Documentation/user/advanced-notation.itely +++ b/Documentation/user/advanced-notation.itely @@ -1097,10 +1097,11 @@ would yield @lilypondfile[raggedright,quote]{tag-filter.ly} -The argument of the @code{\tag} command should be a symbol, or a list -of symbols, for example, +The argument of the @code{\tag} command should be a symbol. It's +possible to put multiple tags on a piece of music, with multiple +@code{\tag} entries, @example -\tag #'(original-part transposed-part) @dots{} + \tag #'original-part \tag #'transposed-part @dots{} @end example diff --git a/THANKS b/THANKS index adf32cc13c..6a8d315dec 100644 --- a/THANKS +++ b/THANKS @@ -16,10 +16,10 @@ Bruce Fairchild Cameron Horsburgh Heikki Junes Joe Neeman +Nicolas Sceaux Sven Axelsson +Werner Lemberg Yoshinobu Ishizaki -Nicolas Sceaux - SPONSORS @@ -36,6 +36,7 @@ Kris Shaffer Mark van den Borre Nancho Alvarez Nicolas Sceaux +Sean Reed Steve Doonan Sven Axelsson Trent Johnston diff --git a/input/regression/grob-tweak.ly b/input/regression/grob-tweak.ly new file mode 100644 index 0000000000..baf6ef1d6a --- /dev/null +++ b/input/regression/grob-tweak.ly @@ -0,0 +1,22 @@ +\header +{ + + texidoc = "With the @code{\tweak} function, individual grobs that + are directly caused by events may be tuned directly." + +} + +\version "2.7.22" +\paper { + raggedright = ##t +} + +{ + \set fingeringOrientations = #'(right) + < + \tweak #'font-size #3 c + \tweak #'color #red d-\tweak #'font-size #8 -4 + \tweak #'style #'cross g + \tweak #'duration-log #1 a + >4 +} diff --git a/lily/auto-beam-engraver.cc b/lily/auto-beam-engraver.cc index cdf0ad31df..9609e40aa0 100644 --- a/lily/auto-beam-engraver.cc +++ b/lily/auto-beam-engraver.cc @@ -334,7 +334,7 @@ Auto_beam_engraver::acknowledge_stem (Grob_info info) { check_bar_property (); Item *stem = dynamic_cast (info.grob ()); - Music *m = info.music_cause (); + Music *m = info.ultimate_music_cause (); if (!m->is_mus_type ("rhythmic-event")) { programming_error ("stem must have rhythmic structure"); diff --git a/lily/beam-engraver.cc b/lily/beam-engraver.cc index 102af1f2ac..4ba9dd7a99 100644 --- a/lily/beam-engraver.cc +++ b/lily/beam-engraver.cc @@ -221,52 +221,55 @@ Beam_engraver::acknowledge_rest (Grob_info info) } } + + void Beam_engraver::acknowledge_stem (Grob_info info) { - if (beam_) + if (!beam_) + return; + + Moment now = now_mom (); + if (!valid_start_point ()) + return; + + Item *stem = dynamic_cast (info.grob ()); + if (Stem::get_beam (stem)) + return; + + + + Music *m = info.ultimate_music_cause (); + if (!m->is_mus_type ("rhythmic-event")) { - Moment now = now_mom (); - - if (!valid_start_point ()) - return; - - Item *stem = dynamic_cast (info.grob ()); - if (Stem::get_beam (stem)) - return; - - Music *m = info.music_cause (); - if (!m->is_mus_type ("rhythmic-event")) - { - String s = _ ("stem must have Rhythmic structure"); - if (info.music_cause ()) - info.music_cause ()->origin ()->warning (s); - else - ::warning (s); - - return; - } + String s = _ ("stem must have Rhythmic structure"); + if (info.music_cause ()) + info.music_cause ()->origin ()->warning (s); + else + ::warning (s); - last_stem_added_at_ = now; - int durlog = unsmob_duration (m->get_property ("duration"))->duration_log (); - if (durlog <= 2) - { - m->origin ()->warning (_ ("stem doesn't fit in beam")); - prev_start_ev_->origin ()->warning (_ ("beam was started here")); - /* - don't return, since + return; + } - [r4 c8] can just as well be modern notation. - */ - } + last_stem_added_at_ = now; + int durlog = unsmob_duration (m->get_property ("duration"))->duration_log (); + if (durlog <= 2) + { + m->origin ()->warning (_ ("stem doesn't fit in beam")); + prev_start_ev_->origin ()->warning (_ ("beam was started here")); + /* + don't return, since - stem->set_property ("duration-log", - scm_from_int (durlog)); - Moment stem_location = now - beam_start_mom_ + beam_start_location_; - beam_info_->add_stem (stem_location, - max (durlog- 2, 0)); - Beam::add_stem (beam_, stem); + [r4 c8] can just as well be modern notation. + */ } + + stem->set_property ("duration-log", + scm_from_int (durlog)); + Moment stem_location = now - beam_start_mom_ + beam_start_location_; + beam_info_->add_stem (stem_location, + max (durlog- 2, 0)); + Beam::add_stem (beam_, stem); } ADD_ACKNOWLEDGER (Beam_engraver, stem); diff --git a/lily/font-config-scheme.cc b/lily/font-config-scheme.cc index 79b069befa..279ffb57b3 100644 --- a/lily/font-config-scheme.cc +++ b/lily/font-config-scheme.cc @@ -29,7 +29,7 @@ display_fontset (FcFontSet *fs) "designsize", 0, &str) == FcResultMatch) printf ("designsize %s\n ", str); - printf ("%s\n", font); + printf ("%s\n", (const char*) font); free (font); } } diff --git a/lily/grob-info.cc b/lily/grob-info.cc index be4a41c6c2..4ffbcf9c15 100644 --- a/lily/grob-info.cc +++ b/lily/grob-info.cc @@ -27,7 +27,7 @@ Grob_info::Grob_info () } Music * -Grob_info::music_cause () +Grob_info::music_cause () const { SCM cause = grob_->get_property ("cause"); return unsmob_music (cause); @@ -65,3 +65,16 @@ Grob_info::item () const { return dynamic_cast (grob_); } + +Music * +Grob_info::ultimate_music_cause () const +{ + SCM cause = grob_->self_scm (); + while (unsmob_grob (cause)) + { + cause = unsmob_grob (cause)->get_property ("cause"); + } + + return unsmob_music (cause); +} + diff --git a/lily/include/grob-info.hh b/lily/include/grob-info.hh index 9dd40fea00..61b903b64b 100644 --- a/lily/include/grob-info.hh +++ b/lily/include/grob-info.hh @@ -27,7 +27,8 @@ public: Translator *origin_translator () const { return origin_trans_; } Context *context () const; - Music *music_cause (); + Music *music_cause () const; + Music *ultimate_music_cause () const; Link_array origin_contexts (Translator *) const; Grob_info (Translator *, Grob *); Grob_info (); diff --git a/lily/lily-lexer.cc b/lily/lily-lexer.cc index 7a8deb6dc3..03ba282520 100644 --- a/lily/lily-lexer.cc +++ b/lily/lily-lexer.cc @@ -73,7 +73,6 @@ static Keyword_ent the_key_tab[] {"set", SET}, {"simultaneous", SIMULTANEOUS}, {"skip", SKIP}, - {"tag", TAG}, {"tempo", TEMPO}, {"time", TIME_T}, {"times", TIMES}, diff --git a/lily/note-head-line-engraver.cc b/lily/note-head-line-engraver.cc index 34b6945088..a7becd06ef 100644 --- a/lily/note-head-line-engraver.cc +++ b/lily/note-head-line-engraver.cc @@ -97,6 +97,7 @@ Note_head_line_engraver::stop_translation_timestep () } #include "translator.icc" + ADD_ACKNOWLEDGER (Note_head_line_engraver, rhythmic_head); ADD_TRANSLATOR (Note_head_line_engraver, /* doc */ "Engrave a line between two note heads, for example a glissando. If " diff --git a/lily/parser.yy b/lily/parser.yy index 70f35f5000..4b250d0966 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -1,5 +1,3 @@ -%{ // -*-Fundamental-*- - /* parser.yy -- Bison/C++ parser for LilyPond @@ -9,6 +7,54 @@ Jan Nieuwenhuizen */ +%{ + +#define YYERROR_VERBOSE 1 +#define YYPARSE_PARAM my_lily_parser +#define YYLEX_PARAM my_lily_parser +#define THIS\ + ((Lily_parser *) my_lily_parser) + +#define yyerror THIS->parser_error + +/* We use custom location type: Input objects */ +#define YYLTYPE Input +#define YYLLOC_DEFAULT(Current,Rhs,N) \ + ((Current).set_location ((Rhs)[1], (Rhs)[N])) + + +%} + +/* We use SCMs to do strings, because it saves us the trouble of +deleting them. Let's hope that a stack overflow doesnt trigger a move +of the parse stack onto the heap. */ + +%left PREC_TOP +%left ADDLYRICS +%left PREC_BOT + +%expect 1 + +/* One shift/reduce problem + +1. \repeat + \repeat .. \alternative + + \repeat { \repeat .. \alternative } + +or + + \repeat { \repeat } \alternative +*/ + + +%pure_parser +%locations + + + +%{ // -*-Fundamental-*- + /* FIXME: @@ -47,174 +93,8 @@ using namespace std; #include "warn.hh" #include "music.hh" -#define MY_MAKE_MUSIC(x) make_music_by_name (ly_symbol2scm (x)) - -Music *property_op_to_music (SCM op); -Music *context_spec_music (SCM type, SCM id, Music *m, SCM ops); -SCM get_next_unique_context_id (); -SCM get_next_unique_lyrics_context_id (); - -#undef _ -#if !HAVE_GETTEXT -#define _(x) x -#else -#include -#define _(x) gettext (x) -#endif - -#define YYERROR_VERBOSE 1 - -#define YYPARSE_PARAM my_lily_parser -#define YYLEX_PARAM my_lily_parser -#define THIS\ - ((Lily_parser *) my_lily_parser) - -#define yyerror THIS->parser_error - -/* We use custom location type: Input objects */ -#define YYLTYPE Input -#define YYLLOC_DEFAULT(Current,Rhs,N) \ - ((Current).set_location ((Rhs)[1], (Rhs)[N])) - - -/* Add symbols to the TAGS field of a music object. */ - -void -tag_music (Music *m, SCM tag, Input ip) -{ - SCM tags = m->get_property ("tags"); - if (scm_is_symbol (tag)) - tags = scm_cons (tag, tags); - else if (ly_is_list (tag)) - tags = ly_append2 (tag, tags); - else - ip.warning (_ ("tag must be symbol or list of symbols")); - - m->set_property ("tags", tags); -} - -bool -is_regular_identifier (SCM id) -{ - String str = ly_scm2string (id); - char const *s = str.to_str0 (); - - bool v = true; -#if 0 - isalpha (*s); - s++; -#endif - while (*s && v) - { - v = v && isalnum (*s); - s++; - } - return v; -} - - -SCM -get_first_context_id (SCM type, Music *m) -{ - SCM id = m->get_property ("context-id"); - if (SCM_BOOL_T == scm_equal_p (m->get_property ("context-type"), type) - && scm_is_string (m->get_property ("context-id")) - && scm_c_string_length (id) > 0) - { - return id; - } - return SCM_EOL; -} - -SCM -make_simple_markup (SCM a) -{ - return a; -} - -bool -is_duration (int t) -{ - return t && t == 1 << intlog2 (t); -} - -void -set_music_properties (Music *p, SCM a) -{ - for (SCM k = a; scm_is_pair (k); k = scm_cdr (k)) - p->internal_set_property (scm_caar (k), scm_cdar (k)); -} - -SCM -make_chord_step (int step, int alter) -{ - if (step == 7) - alter += FLAT; - - while (step < 0) - step += 7; - Pitch m ((step -1) / 7, (step - 1) % 7, alter); - return m.smobbed_copy (); -} - - -SCM -make_chord (SCM pitch, SCM dur, SCM modification_list) -{ - SCM chord_ctor = ly_lily_module_constant ("construct-chord"); - SCM ch = scm_call_3 (chord_ctor, pitch, dur, modification_list); - - unsmob_music (ch)->protect(); - return ch; -} - -/* Todo: actually also use apply iso. call too ... */ -bool -ly_input_procedure_p (SCM x) -{ - return ly_is_procedure (x) - || (scm_is_pair (x) && ly_is_procedure (scm_car (x))); -} - -Music* -set_property_music (SCM sym, SCM value) -{ - Music *p = MY_MAKE_MUSIC ("PropertySet"); - p->set_property ("symbol", sym); - p->set_property ("value", value); - return p; -} - -Music* -make_music_relative (Pitch start, Music *music) -{ - Music *relative = MY_MAKE_MUSIC ("RelativeOctaveMusic"); - relative->set_property ("element", music->self_scm ()); - - Pitch last = music->to_relative_octave (start); - if (lily_1_8_relative) - music->set_property ("last-pitch", last.smobbed_copy ()); - return relative; -} - -Music* -make_lyric_combine_music (SCM name, Music *music) -{ - Music *combine = MY_MAKE_MUSIC ("LyricCombineMusic"); - combine->set_property ("element", music->self_scm ()); - combine->set_property ("associated-context", name); - return combine; -} - %} -/* We use SCMs to do strings, because it saves us the trouble of -deleting them. Let's hope that a stack overflow doesnt trigger a move -of the parse stack onto the heap. */ - -%left PREC_TOP -%left ADDLYRICS -%left PREC_BOT %union { Book *book; @@ -225,40 +105,41 @@ of the parse stack onto the heap. */ Score *score; int i; } -%{ - -int -yylex (YYSTYPE *s, YYLTYPE *loc, void *v) -{ - Lily_parser *pars = (Lily_parser*) v; - Lily_lexer *lex = pars->lexer_; - - lex->lexval = (void*) s; - lex->lexloc = loc; - lex->prepare_for_next_token (); - return lex->yylex (); -} - - -%} -%expect 1 +%{ -/* One shift/reduce problem +#define MY_MAKE_MUSIC(x) make_music_by_name (ly_symbol2scm (x)) -1. \repeat - \repeat .. \alternative +Music *property_op_to_music (SCM op); +Music *context_spec_music (SCM type, SCM id, Music *m, SCM ops); +SCM get_next_unique_context_id (); +SCM get_next_unique_lyrics_context_id (); - \repeat { \repeat .. \alternative } +#undef _ +#if !HAVE_GETTEXT +#define _(x) x +#else +#include +#define _(x) gettext (x) +#endif -or - \repeat { \repeat } \alternative -*/ +Music *make_lyric_combine_music (SCM name, Music *music); +Music *make_music_relative (Pitch start, Music *music); +Music *run_music_function (Lily_parser *, SCM expr); +Music *set_property_music (SCM sym, SCM value); +SCM get_first_context_id (SCM type, Music *m); +SCM make_chord (SCM pitch, SCM dur, SCM modification_list); +SCM make_chord_step (int step, int alter); +SCM make_simple_markup (SCM a); +bool is_duration (int t); +bool is_regular_identifier (SCM id); +bool ly_input_procedure_p (SCM x); +int yylex (YYSTYPE *s, YYLTYPE *loc, void *v); +void set_music_properties (Music *p, SCM a); -%pure_parser -%locations +%} /* The third option is an alias that will be used to display the syntax error. Bison CVS now correctly handles backslash escapes. @@ -318,7 +199,6 @@ or %token SET "\\set" %token SIMULTANEOUS "\\simultaneous" %token SKIP "\\skip" -%token TAG "\\tag" %token TEMPO "\\tempo" %token TIMES "\\times" %token TRANSPOSE "\\transpose" @@ -435,7 +315,6 @@ If we give names, Bison complains. %type tremolo_type %type Composite_music -%type Generic_prefix_music %type Grouped_music_list %type Music %type Prefix_composite_music @@ -459,7 +338,6 @@ If we give names, Bison complains. %type relative_music %type simple_element %type string_number_event -%type tagged_post_event %type tempo_event %type toplevel_music @@ -474,6 +352,8 @@ If we give names, Bison complains. %type absolute_pitch %type assignment_id %type bare_number +%type music_function_event +%type music_function_chord_body %type bass_figure %type figured_bass_modification %type br_bass_figure @@ -1113,10 +993,7 @@ Generic_prefix_music_scm: | MUSIC_FUNCTION_MARKUP full_markup { $$ = scm_list_3 ($1, make_input (@$), $2); } - | MUSIC_FUNCTION_MUSIC Music { - $$ = scm_list_3 ($1, make_input (@$), $2->self_scm ()); - $2->unprotect (); - } + | MUSIC_FUNCTION_SCM_MUSIC embedded_scm Music { $$ = scm_list_4 ($1, make_input (@$), $2, $3->self_scm ()); $3->unprotect (); @@ -1127,6 +1004,10 @@ Generic_prefix_music_scm: | MUSIC_FUNCTION_SCM_SCM_SCM embedded_scm embedded_scm embedded_scm { $$ = scm_list_5 ($1, make_input (@$), $2, $3, $4); } + | MUSIC_FUNCTION_MUSIC Music { + $$ = scm_list_3 ($1, make_input (@$), $2->self_scm ()); + $2->unprotect (); + } | MUSIC_FUNCTION_SCM_SCM_MUSIC embedded_scm embedded_scm Music { $$ = scm_list_5 ($1, make_input (@$), $2, $3, $4->self_scm ()); } @@ -1154,46 +1035,9 @@ Generic_prefix_music_scm: } ; -Generic_prefix_music: - Generic_prefix_music_scm { - SCM func = scm_car ($1); - Input *loc = unsmob_input (scm_cadr ($1)); - SCM args = scm_cddr ($1); - SCM sig = scm_object_property (func, ly_symbol2scm ("music-function-signature")); - - SCM type_check_proc = ly_lily_module_constant ("type-check-list"); - bool ok = true; - - if (!to_boolean (scm_call_3 (type_check_proc, scm_cadr ($1), sig, args))) - { - THIS->error_level_ = 1; - ok = false; - } - - SCM m = SCM_EOL; - if (ok) - m = scm_apply_0 (func, scm_cons (THIS->self_scm(), - scm_cdr ($1))); - - if (unsmob_music (m)) - { - $$ = unsmob_music (m); - $$->protect (); - } - else - { - if (ok) - loc->error (_ ("music head function must return Music object")); - $$ = MY_MAKE_MUSIC ("Music"); - } - $$->set_spot (*loc); - } - ; - - Prefix_composite_music: - Generic_prefix_music { - $$ = $1; + Generic_prefix_music_scm { + $$ = run_music_function (THIS, $1); } | CONTEXT simple_string '=' simple_string optional_context_mod Music { $$ = context_spec_music ($2, $4, $6, $5); @@ -1262,10 +1106,6 @@ Prefix_composite_music: } | relative_music { $$ = $1; } | re_rhythmed_music { $$ = $1; } - | TAG embedded_scm Music { - tag_music ($3, $2, @$); - $$ = $3; - } ; mode_changing_head: @@ -1689,8 +1529,33 @@ chord_body_element: } $$ = n; } + | music_function_chord_body { + $$ = run_music_function (THIS, $1); + $$->set_spot (@$); + } + ; + +music_function_chord_body: + MUSIC_FUNCTION { + $$ = scm_list_2 ($1, make_input (@$)); + } + | MUSIC_FUNCTION_MUSIC chord_body_element { + $$ = scm_list_3 ($1, make_input (@$), + $2->self_scm ()); + } + | MUSIC_FUNCTION_SCM_MUSIC embedded_scm chord_body_element { + $$ = scm_list_4 ($1, make_input (@$), + $2, $3->self_scm ()); + } + | MUSIC_FUNCTION_SCM_SCM_MUSIC embedded_scm embedded_scm + chord_body_element { + + $$ = scm_list_5 ($1, make_input (@$), + $2, $3, $4->self_scm ()); + } ; + add_quote: ADDQUOTE string Music { SCM adder = ly_lily_module_constant ("add-quotable"); @@ -1847,26 +1712,30 @@ post_events: $$ = scm_cons ($2->self_scm (), $$); $2->unprotect (); } - | post_events tagged_post_event { - $2 -> set_spot (@2); - $$ = scm_cons ($2->self_scm (), $$); - $2->unprotect (); - } ; - -tagged_post_event: - '-' TAG embedded_scm post_event { - tag_music ($4, $3, @$); - $$ = $4; +music_function_event: + MUSIC_FUNCTION_MUSIC post_event { + $$ = scm_list_3 ($1, make_input (@$), $2->self_scm ()); + } + | MUSIC_FUNCTION_SCM_MUSIC embedded_scm post_event { + $$ = scm_list_4 ($1, make_input (@$), $2, $3->self_scm ()); + } + | MUSIC_FUNCTION_SCM_SCM_MUSIC embedded_scm embedded_scm post_event { + $$ = scm_list_5 ($1, make_input (@$), $2, $3, $4->self_scm ()); } ; - + post_event: direction_less_event { $$ = $1; } + | '-' music_function_event { + Music *mus = run_music_function (THIS, $2); + mus->set_spot (@1); + $$ = mus; + } | HYPHEN { if (!THIS->lexer_->is_lyric_state ()) THIS->parser_error (@1, _ ("have to be in Lyric mode for lyrics")); @@ -2834,6 +2703,174 @@ get_next_unique_lyrics_context_id () { static int new_context_count; char s[128]; - snprintf (s, 1024, "uniqueContext%d", new_context_count++); + snprintf (s, sizeof (s)-1, "uniqueContext%d", new_context_count++); return scm_makfrom0str (s); } + + +Music * +run_music_function (Lily_parser *parser, SCM expr) +{ + SCM func = scm_car (expr); + Input *loc = unsmob_input (scm_cadr (expr)); + SCM args = scm_cddr (expr); + SCM sig = scm_object_property (func, ly_symbol2scm ("music-function-signature")); + + SCM type_check_proc = ly_lily_module_constant ("type-check-list"); + bool ok = true; + + if (!to_boolean (scm_call_3 (type_check_proc, scm_cadr (expr), sig, args))) + { + parser->error_level_ = 1; + ok = false; + } + + SCM m = SCM_EOL; + if (ok) + m = scm_apply_0 (func, scm_cons (parser->self_scm(), + scm_cdr (expr))); + + + Music* retval = 0; + if (unsmob_music (m)) + { + retval = unsmob_music (m); + retval->protect (); + } + else + { + if (ok) + loc->error (_ ("music head function must return Music object")); + retval = MY_MAKE_MUSIC ("Music"); + } + retval->set_spot (*loc); + return retval; +} + +bool +is_regular_identifier (SCM id) +{ + String str = ly_scm2string (id); + char const *s = str.to_str0 (); + + bool v = true; +#if 0 + isalpha (*s); + s++; +#endif + while (*s && v) + { + v = v && isalnum (*s); + s++; + } + return v; +} + + +SCM +get_first_context_id (SCM type, Music *m) +{ + SCM id = m->get_property ("context-id"); + if (SCM_BOOL_T == scm_equal_p (m->get_property ("context-type"), type) + && scm_is_string (m->get_property ("context-id")) + && scm_c_string_length (id) > 0) + { + return id; + } + return SCM_EOL; +} + +SCM +make_simple_markup (SCM a) +{ + return a; +} + +bool +is_duration (int t) +{ + return t && t == 1 << intlog2 (t); +} + +void +set_music_properties (Music *p, SCM a) +{ + for (SCM k = a; scm_is_pair (k); k = scm_cdr (k)) + p->internal_set_property (scm_caar (k), scm_cdar (k)); +} + + +SCM +make_chord_step (int step, int alter) +{ + if (step == 7) + alter += FLAT; + + while (step < 0) + step += 7; + Pitch m ((step -1) / 7, (step - 1) % 7, alter); + return m.smobbed_copy (); +} + + +SCM +make_chord (SCM pitch, SCM dur, SCM modification_list) +{ + SCM chord_ctor = ly_lily_module_constant ("construct-chord"); + SCM ch = scm_call_3 (chord_ctor, pitch, dur, modification_list); + + unsmob_music (ch)->protect(); + return ch; +} + + +/* Todo: actually also use apply iso. call too ... */ +bool +ly_input_procedure_p (SCM x) +{ + return ly_is_procedure (x) + || (scm_is_pair (x) && ly_is_procedure (scm_car (x))); +} + +Music* +set_property_music (SCM sym, SCM value) +{ + Music *p = MY_MAKE_MUSIC ("PropertySet"); + p->set_property ("symbol", sym); + p->set_property ("value", value); + return p; +} + +Music* +make_music_relative (Pitch start, Music *music) +{ + Music *relative = MY_MAKE_MUSIC ("RelativeOctaveMusic"); + relative->set_property ("element", music->self_scm ()); + + Pitch last = music->to_relative_octave (start); + if (lily_1_8_relative) + music->set_property ("last-pitch", last.smobbed_copy ()); + return relative; +} + +Music * +make_lyric_combine_music (SCM name, Music *music) +{ + Music *combine = MY_MAKE_MUSIC ("LyricCombineMusic"); + combine->set_property ("element", music->self_scm ()); + combine->set_property ("associated-context", name); + return combine; +} + + +int +yylex (YYSTYPE *s, YYLTYPE *loc, void *v) +{ + Lily_parser *pars = (Lily_parser*) v; + Lily_lexer *lex = pars->lexer_; + + lex->lexval = (void*) s; + lex->lexloc = loc; + lex->prepare_for_next_token (); + return lex->yylex (); +} diff --git a/lily/stem-engraver.cc b/lily/stem-engraver.cc index 052f4d653c..019b05333f 100644 --- a/lily/stem-engraver.cc +++ b/lily/stem-engraver.cc @@ -51,7 +51,7 @@ Stem_engraver::make_stem (Grob_info gi) { /* Announce the cause of the head as cause of the stem. The stem needs a rhythmic structure to fit it into a beam. */ - stem_ = make_item ("Stem", gi.music_cause ()->self_scm ()); + stem_ = make_item ("Stem", gi.grob ()->self_scm ()); /* we take the duration log from the Event, since the duration-log diff --git a/lily/tweak-engraver.cc b/lily/tweak-engraver.cc new file mode 100644 index 0000000000..da8f5375de --- /dev/null +++ b/lily/tweak-engraver.cc @@ -0,0 +1,48 @@ +/* + tweak-engraver.cc -- implement Tweak_engraver + + source file of the GNU LilyPond music typesetter + + (c) 2005 Han-Wen Nienhuys + +*/ + +#include "engraver.hh" + +#include "music.hh" +#include "grob.hh" +#include "translator.icc" + +class Tweak_engraver : public Engraver +{ + TRANSLATOR_DECLARATIONS (Tweak_engraver); + +protected: + DECLARE_ACKNOWLEDGER (grob); +}; + +Tweak_engraver::Tweak_engraver() +{ +} + +void +Tweak_engraver::acknowledge_grob (Grob_info info) +{ + if (Music *music = info.music_cause ()) + { + for (SCM s = music->get_property ("tweaks"); + scm_is_pair (s); s = scm_cdr (s)) + { + info.grob ()->internal_set_property (scm_caar (s), scm_cdar (s)); + } + } +} + +ADD_ACKNOWLEDGER (Tweak_engraver, grob); +ADD_TRANSLATOR (Tweak_engraver, + /* doc */ "Read the @code{tweaks} property from the originating Music event, and set properties." , + + /* create */ "", + /* accept */ "", + /* read */ "", + /* write */ ""); diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index c051a64451..6bc9228970 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -1,18 +1,18 @@ \version "2.7.14" \context { - \name Global + \name "Global" - \accepts Score + \accepts "Score" - \defaultchild Score + \defaultchild "Score" \description "Hard coded entry point for LilyPond. Cannot be tuned." \grobdescriptions #all-grob-descriptions } \context { \type "Engraver_group" - \name Staff + \name "Staff" \consists "Output_property_engraver" \consists "Bar_engraver" @@ -64,8 +64,9 @@ \context { \Staff \type "Engraver_group" - \name DrumStaff - \alias Staff + \name "DrumStaff" + \alias "Staff" + \remove "Accidental_engraver" \remove "Ottava_spanner_engraver" \remove "Key_engraver" @@ -74,9 +75,9 @@ \description "Handles typesetting for percussion." - \denies Voice - \accepts DrumVoice - \defaultchild DrumVoice + \denies "Voice" + \accepts "DrumVoice" + \defaultchild "DrumVoice" clefGlyph = #"clefs.percussion" clefPosition = #0 @@ -86,7 +87,7 @@ \context { \type "Engraver_group" - \name InnerChoirStaff + \name "InnerChoirStaff" \consists "System_start_delimiter_engraver" systemStartDelimiter = #'SystemStartBracket @@ -416,9 +417,9 @@ AncientRemoveEmptyStaffContext = \context { } \context { - \type Score_engraver + \type "Score_engraver" \name "Score" - + \description "This is the top level notation context. No other context can contain a @code{Score} context. This context handles the administration of time signatures. It also makes sure @@ -449,9 +450,10 @@ AncientRemoveEmptyStaffContext = \context { \consists "Vertical_align_engraver" \consists "Stanza_number_align_engraver" \consists "Bar_number_engraver" - \consists "Span_arpeggio_engraver" - + \consists "Tweak_engraver" + \defaultchild "Staff" + \accepts "Staff" \accepts "RhythmicStaff" \accepts "TabStaff" @@ -468,7 +470,7 @@ AncientRemoveEmptyStaffContext = \context { \accepts "Devnull" \accepts "NoteNames" \accepts "FiguredBass" - + soloText = #"Solo" soloIIText = #"Solo II" aDueText = #"a2" diff --git a/ly/music-functions-init.ly b/ly/music-functions-init.ly index 798f46641d..0d7aeb26c0 100644 --- a/ly/music-functions-init.ly +++ b/ly/music-functions-init.ly @@ -6,6 +6,43 @@ #(use-modules (srfi srfi-1)) + +tweak = #(def-music-function (parser location sym val arg) + (symbol? scheme? ly:music?) + + "Add @code{sym . val} to the @code{tweaks} property of @var{arg}." + + + (set! + (ly:music-property arg 'tweaks) + (acons sym val + (ly:music-property arg 'tweaks))) + arg) + + + +tag = #(def-music-function (parser location tag arg) + (symbol? ly:music?) + + "Add @var{tag} to the @code{tags} property of @var{arg}." + + (set! + (ly:music-property arg 'tags) + (cons tag + (ly:music-property arg 'tags))) + arg) + +tag = #(def-music-function (parser location tag arg) + (symbol? ly:music?) + + "Add @var{tag} to the @code{tags} property of @var{arg}." + + (set! + (ly:music-property arg 'tags) + (cons tag + (ly:music-property arg 'tags))) + arg) + applyMusic = #(def-music-function (parser location func music) (procedure? ly:music?) (func music)) diff --git a/python/convertrules.py b/python/convertrules.py index bf0e4d1aa8..6868b4937b 100644 --- a/python/convertrules.py +++ b/python/convertrules.py @@ -2651,3 +2651,16 @@ def conv (str): conversions.append (((2, 7, 15), conv, '''Use grob closures iso. XY-offset-callbacks.''')) + + +def conv (str): + def sub_syms (m): + syms = m.group (1).split () + tags = ["\\tag #'%s" % s for s in syms] + return ' '.join (tags) + + str = re.sub (r"\\tag #'\(([^)]+)\)", sub_syms, str) + return str + +conversions.append (((2, 7, 22), conv, + """\tag #'(a b) -> \tag #'a \tag #'b""" )) diff --git a/python/musicexp.py b/python/musicexp.py index b2b5846a6f..43c75c870f 100644 --- a/python/musicexp.py +++ b/python/musicexp.py @@ -25,6 +25,11 @@ class Output_printer: self.output_state_stack = [Output_stack_element()] self._skipspace = False self.last_duration = None + + def dump_version (self): + self.newline () + self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"') + self.newline () def get_indent (self): return self.nesting * self.indent diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm index c3be6e3886..28c9b1c83e 100644 --- a/scm/define-grobs.scm +++ b/scm/define-grobs.scm @@ -134,11 +134,8 @@ ledgered-interface)))))) (Arpeggio - . ( - - (X-extent . ,Arpeggio::width) + . ((X-extent . ,Arpeggio::width) (stencil . ,Arpeggio::print) - (Y-offset . ,Staff_symbol_referencer::callback) (X-offset . ,Side_position_interface::x_aligned_side) (direction . -1) diff --git a/scm/define-music-properties.scm b/scm/define-music-properties.scm index 58d7eea429..689f81180e 100644 --- a/scm/define-music-properties.scm +++ b/scm/define-music-properties.scm @@ -83,6 +83,9 @@ It must take a single argument, being the context.") (quoted-context-type ,symbol? "The name of the context to direct quotes to, eg., @code{Voice}.") (quoted-context-id ,string? "The id of the context to direct quotes to, eg., @code{cue}.") (to-relative-callback ,procedure? "How to transform a piece of music to relative pitches") + (tweaks ,list? "An alist of properties to override in the backend +for the grob made of this event.") + (repeat-count ,integer? "do a @code{\repeat} how ofen?") (span-direction ,ly:dir? "Does this start or stop a spanner?") (split-list ,list? "splitting moments for part combiner.") -- 2.39.5