diff options
author | Nicolas Sceaux <nicolas.sceaux@free.fr> | 2009-11-11 19:59:09 +0100 |
---|---|---|
committer | Nicolas Sceaux <nicolas.sceaux@free.fr> | 2009-11-15 11:52:41 +0100 |
commit | e26f468ce5bdb4738bb34d6ad200cd888c6011ac (patch) | |
tree | d59ea35e63af445b748e5beada7a90e823f471a1 | |
parent | 73cb322149a8fea9aee2b6c5b5281207a34cfe3c (diff) |
Issue #768: Chord repetition shortcut
In the lexer, add a chord repetition state, holding the repetition
symbol (like note names, but for chord repetition), the repetition
function used to copy the previous chord, and a slot to save the
previous chord. Use the repetition symbol to detect a chord
repetition when lexing.
In the parser, when a note chord is found, save it (it becomes
previous chord). When a chord repetition token is found, make a chord
using the repetition function and the previous chord.
The repetition symbol and function are initialized in
ly/chord-repetition-init.ly. The repetition symbol defaults to `q' (as
quote or qord -- as suggested Werner). The function copies the
pitches, but not articulations.
-rw-r--r-- | Documentation/changes.tely | 9 | ||||
-rw-r--r-- | Documentation/notation/simultaneous.itely | 26 | ||||
-rw-r--r-- | input/regression/chord-repetition.ly | 12 | ||||
-rw-r--r-- | input/regression/quote-kill-cues.ly | 6 | ||||
-rw-r--r-- | lily/include/lily-lexer.hh | 16 | ||||
-rw-r--r-- | lily/lexer.ll | 3 | ||||
-rw-r--r-- | lily/lily-lexer.cc | 2 | ||||
-rw-r--r-- | lily/lily-parser-scheme.cc | 26 | ||||
-rw-r--r-- | lily/parser.yy | 13 | ||||
-rw-r--r-- | ly/chord-repetition-init.ly | 34 | ||||
-rw-r--r-- | ly/declarations-init.ly | 2 | ||||
-rw-r--r-- | scm/ly-syntax-constructors.scm | 5 |
12 files changed, 147 insertions, 7 deletions
diff --git a/Documentation/changes.tely b/Documentation/changes.tely index d5ad52b382..0c2eea74e4 100644 --- a/Documentation/changes.tely +++ b/Documentation/changes.tely @@ -63,6 +63,12 @@ which scares away people. @end ignore +@item +Chords can be repeated using the @code{q} shortcut: + +@lilypond[verbatim,quote,relative=2] +<c e g>8.-^ q16 q4-^ +@end lilypond @item Paper margin defaults, as specified in @file{ly/@/paper@/-defaults@/-init@/.ly}, apply @@ -81,8 +87,7 @@ added. @item In addition to the existing @code{\hspace} markup command, a new @code{\vspace} command has been added to provide an easy -and flexible way to add vertical space in markups. This feature -is based on Nicolas Sceaux's work. +and flexible way to add vertical space in markups. @item The direction of manual beams can be set with @code{^[} and @code{_[}. diff --git a/Documentation/notation/simultaneous.itely b/Documentation/notation/simultaneous.itely index 8699239107..b2b652d9c6 100644 --- a/Documentation/notation/simultaneous.itely +++ b/Documentation/notation/simultaneous.itely @@ -31,6 +31,7 @@ This section discusses simultaneous notes inside the same voice. @menu * Chorded notes:: +* Chord repetition:: * Simultaneous expressions:: * Clusters:: @end menu @@ -63,7 +64,6 @@ pitch is the @emph{first} pitch of the preceding chord. For more information about chords, see @ref{Chord notation}. - @seealso Music Glossary: @rglos{chord}. @@ -78,6 +78,30 @@ Snippets: @rlsr{Simultaneous notes}. +@node Chord repetition +@unnumberedsubsubsec Chord repetition + +In order to save typing, a shortcut can be used to repeat the preceding +chord. The chord repetition symbol is @code{q}: + +@lilypond[verbatim,quote,relative=1] +<c e g> q q q +@end lilypond + +As in the case of regular chords, the chord repetition symbol can be +followed by a duration and articulations. Only the pitches of the +previous chord are duplicated; articulations, dynamics, etc, are not +repeated. + +@lilypond[verbatim,quote,relative=1] +<c e g>8\p q q4-| q8.^"text" q16 q4-| +@end lilypond + +@seealso +Installed Files: +@file{ly/@/chord-repetition-init@/.ly}. + + @node Simultaneous expressions @unnumberedsubsubsec Simultaneous expressions diff --git a/input/regression/chord-repetition.ly b/input/regression/chord-repetition.ly new file mode 100644 index 0000000000..f84f2807f1 --- /dev/null +++ b/input/regression/chord-repetition.ly @@ -0,0 +1,12 @@ +\version "2.13.8" + +\header { + texidoc = " +A repetition symbol can be used to repeat the previous chord +and save typing. Only note events are copied. +" +} + +\relative c' { + <c e g>8\p( q) q4-| q8.\(^"text" q16 q4-|\) +} diff --git a/input/regression/quote-kill-cues.ly b/input/regression/quote-kill-cues.ly index 79541220bf..730a210b25 100644 --- a/input/regression/quote-kill-cues.ly +++ b/input/regression/quote-kill-cues.ly @@ -8,11 +8,11 @@ mus = \relative c' { c2 c c c c c c c } \addQuote #"M" \mus -q = \relative c' { +quot = \relative c' { d2 \quoteDuring #"M" { s1 } e2 \cueDuring #"M" #UP { s1 } f2 } \score { << - \q - \killCues \q + \quot + \killCues \quot >> } diff --git a/lily/include/lily-lexer.hh b/lily/include/lily-lexer.hh index 4062e3410f..f290f4ea8b 100644 --- a/lily/include/lily-lexer.hh +++ b/lily/include/lily-lexer.hh @@ -19,6 +19,20 @@ bool busy_parsing (); void kill_lexer (); void set_lexer (); +struct Chord_repetition +{ + Chord_repetition () + { + last_chord_ = SCM_EOL; + repetition_function_ = SCM_EOL; + repetition_symbol_ = SCM_EOL; + } + + SCM repetition_symbol_; + SCM repetition_function_; + SCM last_chord_; +}; + class Lily_lexer : public Includable_lexer { DECLARE_SMOBS (Lily_lexer); @@ -48,6 +62,8 @@ public: SCM chordmodifier_tab_; SCM pitchname_tab_stack_; + Chord_repetition chord_repetition_; + int error_level_; Input last_input_; diff --git a/lily/lexer.ll b/lily/lexer.ll index 1ad6b667da..f38084642b 100644 --- a/lily/lexer.ll +++ b/lily/lexer.ll @@ -830,6 +830,9 @@ Lily_lexer::scan_bare_word (string str) yylval.scm = scm_cdr (handle); return CHORD_MODIFIER; } + if ((chord_repetition_.repetition_symbol_ != SCM_EOL) + && to_boolean (scm_equal_p (chord_repetition_.repetition_symbol_, sym))) + return CHORD_REPETITION; } yylval.scm = ly_string2scm (str); diff --git a/lily/lily-lexer.cc b/lily/lily-lexer.cc index 25d2c98c25..27c3bfef3b 100644 --- a/lily/lily-lexer.cc +++ b/lily/lily-lexer.cc @@ -95,6 +95,7 @@ Lily_lexer::Lily_lexer (Sources *sources, Lily_parser *parser) error_level_ = 0; is_main_input_ = false; start_module_ = SCM_EOL; + chord_repetition_ = Chord_repetition (); smobify_self (); add_scope (ly_make_anonymous_module (false)); @@ -111,6 +112,7 @@ Lily_lexer::Lily_lexer (Lily_lexer const &src, Lily_parser *parser) pitchname_tab_stack_ = src.pitchname_tab_stack_; sources_ = src.sources_; start_module_ = SCM_EOL; + chord_repetition_ = Chord_repetition (); error_level_ = src.error_level_; is_main_input_ = src.is_main_input_; diff --git a/lily/lily-parser-scheme.cc b/lily/lily-parser-scheme.cc index f58f2ea0fa..023237c3cc 100644 --- a/lily/lily-parser-scheme.cc +++ b/lily/lily-parser-scheme.cc @@ -212,6 +212,32 @@ LY_DEFINE (ly_parser_set_note_names, "ly:parser-set-note-names", return SCM_UNSPECIFIED; } +LY_DEFINE (ly_parser_set_repetition_symbol, "ly:parser-set-repetition-symbol", + 2, 0, 0, (SCM parser, SCM sym), + "Replace the current repetition symbol in @var{parser}." + " @var{sym} is the new repetition symbol.") +{ + LY_ASSERT_SMOB (Lily_parser, parser, 1); + Lily_parser *p = unsmob_lily_parser (parser); + + p->lexer_->chord_repetition_.repetition_symbol_ = sym; + + return SCM_UNSPECIFIED; +} + +LY_DEFINE (ly_parser_set_repetition_function, "ly:parser-set-repetition-function", + 2, 0, 0, (SCM parser, SCM fun), + "Replace the current repetition function in @var{parser}." + " @var{fun} is the new repetition function.") +{ + LY_ASSERT_SMOB (Lily_parser, parser, 1); + Lily_parser *p = unsmob_lily_parser (parser); + + p->lexer_->chord_repetition_.repetition_function_ = fun; + + return SCM_UNSPECIFIED; +} + LY_DEFINE (ly_parser_output_name, "ly:parser-output-name", 1, 0, 0, (SCM parser), "Return the base name of the output file.") diff --git a/lily/parser.yy b/lily/parser.yy index 584b6e7853..d93a1767e1 100644 --- a/lily/parser.yy +++ b/lily/parser.yy @@ -266,6 +266,7 @@ If we give names, Bison complains. %token <scm> BOOK_IDENTIFIER %token <scm> CHORDMODIFIER_PITCH %token <scm> CHORD_MODIFIER +%token <scm> CHORD_REPETITION %token <scm> CONTEXT_DEF_IDENTIFIER %token <scm> DRUM_PITCH %token <scm> DURATION_IDENTIFIER @@ -1001,7 +1002,9 @@ simultaneous_music: ; simple_music: - event_chord + event_chord { + PARSER->lexer_->chord_repetition_.last_chord_ = $$; + } | MUSIC_IDENTIFIER | music_property_def | context_change @@ -1414,6 +1417,14 @@ event_chord: i.set_location (@1, @2); $$ = MAKE_SYNTAX ("event-chord", i, elts); } + | CHORD_REPETITION optional_notemode_duration post_events { + Input i; + i.set_location (@1, @3); + $$ = MAKE_SYNTAX ("repetition-chord", i, + PARSER->lexer_->chord_repetition_.last_chord_, + PARSER->lexer_->chord_repetition_.repetition_function_, + $2, $3); + } | MULTI_MEASURE_REST optional_notemode_duration post_events { Input i; i.set_location (@1, @3); diff --git a/ly/chord-repetition-init.ly b/ly/chord-repetition-init.ly new file mode 100644 index 0000000000..3ff4578b60 --- /dev/null +++ b/ly/chord-repetition-init.ly @@ -0,0 +1,34 @@ +\version "2.13.8" +%{ +Two functions define the chord repetition behavior, and may +be invoked by the user to customize it. + +ly:parser-set-repetition-symbol + set the chord repetition shortcut. + `q' is the default value set in this file. + +ly:parser-set-repetition-function + set the function that is invoked when a chord repetition symbol + is encountered by the parser: a three argument function + (previous-chord, duration, list of articulations) which is supposed + to return a new chord. + `default-repeat-chord' is the default function set in this file. +%} + +#(define-public (default-repeat-chord previous-chord duration articulations) + "Copy the previous chord, filter out events which are not notes, set the +chord duration, add articulations." + (let ((new-chord (ly:music-deep-copy previous-chord))) + (set! (ly:music-property new-chord 'elements) + (append! articulations + (filter (lambda (event) + (eqv? (ly:music-property event 'name) 'NoteEvent)) + (ly:music-property new-chord 'elements)))) + (for-each (lambda (event) + (if (ly:duration? (ly:music-property event 'duration)) + (set! (ly:music-property event 'duration) duration))) + (ly:music-property new-chord 'elements)) + new-chord)) + +#(ly:parser-set-repetition-symbol parser 'q) +#(ly:parser-set-repetition-function parser default-repeat-chord) diff --git a/ly/declarations-init.ly b/ly/declarations-init.ly index f822e0f3de..1ce34b8f8d 100644 --- a/ly/declarations-init.ly +++ b/ly/declarations-init.ly @@ -19,6 +19,8 @@ maxima = #(ly:make-duration -3 0) \include "chord-modifiers-init.ly" \include "script-init.ly" +\include "chord-repetition-init.ly" + % declarations for standard directions left = #-1 right = #1 diff --git a/scm/ly-syntax-constructors.scm b/scm/ly-syntax-constructors.scm index 8eefe63b71..3ee82f09f6 100644 --- a/scm/ly-syntax-constructors.scm +++ b/scm/ly-syntax-constructors.scm @@ -131,6 +131,11 @@ 'duration duration 'origin location)) +(define-ly-syntax (repetition-chord parser location previous-chord repetition-function duration articulations) + (let ((new-chord (repetition-function previous-chord duration articulations))) + (set! (ly:music-property new-chord 'origin) location) + new-chord)) + (define-ly-syntax-simple (context-specification type id mus ops create-new) (let* ((type-sym (if (symbol? type) type (string->symbol type))) (csm (context-spec-music mus type-sym id))) |