]> git.donarmstrong.com Git - lilypond.git/commitdiff
Issue #768: Chord repetition shortcut
authorNicolas Sceaux <nicolas.sceaux@free.fr>
Wed, 11 Nov 2009 18:59:09 +0000 (19:59 +0100)
committerNicolas Sceaux <nicolas.sceaux@free.fr>
Sun, 15 Nov 2009 10:52:41 +0000 (11:52 +0100)
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.

12 files changed:
Documentation/changes.tely
Documentation/notation/simultaneous.itely
input/regression/chord-repetition.ly [new file with mode: 0644]
input/regression/quote-kill-cues.ly
lily/include/lily-lexer.hh
lily/lexer.ll
lily/lily-lexer.cc
lily/lily-parser-scheme.cc
lily/parser.yy
ly/chord-repetition-init.ly [new file with mode: 0644]
ly/declarations-init.ly
scm/ly-syntax-constructors.scm

index d5ad52b382bbe22626136114a83549ffeb971e57..0c2eea74e45d75ee35ad321e41f59947949e8572 100644 (file)
@@ -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{_[}.
index 8699239107a4292739b9c8c98b4d7a0c6743df5a..b2b652d9c640ec54bcf78d524f4f0e6394c27625 100644 (file)
@@ -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 (file)
index 0000000..f84f280
--- /dev/null
@@ -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-|\)
+}
index 79541220bff294da937539e37965a70a3482678a..730a210b25ffe19746ca5dd4930b0b577ba06ff1 100644 (file)
@@ -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
 >> }
index 4062e3410fe1a1e3e8d2c6f883140fe83f87e934..f290f4ea8b169d50b7ac06e0e4a9e4d2474f1057 100644 (file)
@@ -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_;
 
index 1ad6b667da93a9b11e896be7958ab735a04738eb..f38084642b83ff3d51144ae759eb8586412be69e 100644 (file)
@@ -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);
index 25d2c98c25230edc1c6715237f7a8f286af569c1..27c3bfef3bec056b0310fde28abe8ac07244909e 100644 (file)
@@ -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_;
index f58f2ea0fad9a773b2c6da8f7979b4f35b54cba8..023237c3cccf793c8cc69595a1d630c5fcff040c 100644 (file)
@@ -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.")
index 584b6e78531d0dbb4906568dd7b07137dceffbfb..d93a1767e1502e294dd48abe215496e48fb8531a 100644 (file)
@@ -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 (file)
index 0000000..3ff4578
--- /dev/null
@@ -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)
index f822e0f3dea4ba7ca32ae47a53674b3feb3d728f..1ce34b8f8d75a4f237a32e08672786855e290687 100644 (file)
@@ -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
index 8eefe63b714fd0cb3944a5dd38e5b083d500a38f..3ee82f09f6e6a9f1053e5be695e030a84d640176 100644 (file)
              '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)))