summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Sceaux <nicolas.sceaux@free.fr>2009-11-11 19:59:09 +0100
committerNicolas Sceaux <nicolas.sceaux@free.fr>2009-11-15 11:52:41 +0100
commite26f468ce5bdb4738bb34d6ad200cd888c6011ac (patch)
treed59ea35e63af445b748e5beada7a90e823f471a1
parent73cb322149a8fea9aee2b6c5b5281207a34cfe3c (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.tely9
-rw-r--r--Documentation/notation/simultaneous.itely26
-rw-r--r--input/regression/chord-repetition.ly12
-rw-r--r--input/regression/quote-kill-cues.ly6
-rw-r--r--lily/include/lily-lexer.hh16
-rw-r--r--lily/lexer.ll3
-rw-r--r--lily/lily-lexer.cc2
-rw-r--r--lily/lily-parser-scheme.cc26
-rw-r--r--lily/parser.yy13
-rw-r--r--ly/chord-repetition-init.ly34
-rw-r--r--ly/declarations-init.ly2
-rw-r--r--scm/ly-syntax-constructors.scm5
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)))