<c e g>8\p q q4-| q8.^"text" q16 q4-|
@end lilypond
+Note chords (entered using angle brackets) only are memorized in order
+to be repeated by @code{q}: it is possible to repeat a chord even if for
+instance a simple note (without angle brackets) or a rest have been
+entered meanwhile.
+
+@lilypond[verbatim,quote,relative=1]
+<c e g>8 c' q c r4 q
+@end lilypond
+
@seealso
Installed Files:
@file{ly/@/chord-repetition-init@/.ly}.
--- /dev/null
+\version "2.13.9"
+
+\header {
+ texidoc = "
+Chord repetition handles \\relative mode: the repeated chords have
+the same octaves as the original one.
+"
+}
+
+{
+ <c''' d'' g''>4^"absolute" q q q
+ \relative c' { <c'' d, g>4^"relative" q q q }
+}
\ No newline at end of file
DECLARE_SCHEME_CALLBACK (first_start_callback, (SCM));
DECLARE_SCHEME_CALLBACK (simultaneous_relative_callback, (SCM, SCM));
DECLARE_SCHEME_CALLBACK (event_chord_relative_callback, (SCM, SCM));
+ DECLARE_SCHEME_CALLBACK (repeated_chord_relative_callback, (SCM, SCM));
Pitch do_relative_octave (Pitch p, bool b);
p, true).smobbed_copy ();
}
+MAKE_SCHEME_CALLBACK (Music_sequence, repeated_chord_relative_callback, 2);
+SCM
+Music_sequence::repeated_chord_relative_callback (SCM music, SCM pitch)
+{
+ Music *me = unsmob_music (music);
+ Music *repeated_chord = unsmob_music (me->get_property ("element"));
+ Music *original_chord = unsmob_music (me->get_property ("original-chord"));
+
+ /* A repeated chord octave is not computed from the previous pitch,
+ * (this function `pitch' argument), but from the original chord, so
+ * that repeated chords have the same octave have the original chord,
+ * even though other simple notes have been entered meanwhile.
+ */
+ assert (repeated_chord);
+ Pitch *p = 0;
+ /* Get the original chord first pitch */
+ if (original_chord)
+ {
+ for (SCM s = original_chord->get_property ("elements"); scm_is_pair (s); s = scm_cdr (s))
+ {
+ if (Music *m = unsmob_music (scm_car (s)))
+ {
+ p = unsmob_pitch (m->get_property ("pitch"));
+ if (p)
+ break;
+ }
+ }
+ }
+ /* Use the `pitch' argument if no pitch found in original chord. */
+ if (! p)
+ p = unsmob_pitch (pitch);
+
+ /* Change the first note pitch to -1, to avoid octaviation. Indeed,
+ * the first pitch should be the same as the original chord first
+ * pitch. */
+ for (SCM s = repeated_chord->get_property ("elements"); scm_is_pair (s); s = scm_cdr (s))
+ {
+ if (Music *m = unsmob_music (scm_car (s)))
+ {
+ Pitch *first_pitch = unsmob_pitch (m->get_property ("pitch"));
+ if (first_pitch)
+ {
+ Pitch new_pitch = Pitch (-1,
+ first_pitch->get_notename (),
+ first_pitch->get_alteration ());
+ m->set_property ("pitch", new_pitch.smobbed_copy ());
+ break;
+ }
+ }
+ }
+ music_list_to_relative (repeated_chord->get_property ("elements"), *p, true).smobbed_copy ();
+ /* Return `pitch' instead of the repeated chord first pitch,
+ * because `pitch' is the last explicitly entered pitch */
+ return pitch;
+}
/* TODO: Create a special case that avoids the creation of
EventChords around simple_elements that have no post_events?
*/
- /* event_chords like simple notes, note chords, etc, are
- saved into PARSER->lexer_->chord_repetition_ so that
- the chord repetition mechanism can copy them when a
- chord repetition symbol is found
- */
simple_chord_elements post_events {
SCM elts = ly_append2 ($1, scm_reverse_x ($2, SCM_EOL));
* i = @$; */
i.set_location (@1, @2);
$$ = MAKE_SYNTAX ("event-chord", i, elts);
- PARSER->lexer_->chord_repetition_.last_chord_ = $$;
}
| CHORD_REPETITION optional_notemode_duration post_events {
Input i;
$$ = MAKE_SYNTAX ("multi-measure-rest", i, $2, $3);
}
| command_element
+ /* note chord elements are memorized into
+ PARSER->lexer_->chord_repetition_ so that the chord repetition
+ mechanism copy them when a chord repetition symbol is found
+ */
| note_chord_element {
PARSER->lexer_->chord_repetition_.last_chord_ = $$;
}
-\version "2.13.8"
+%%% -*- Mode: Scheme -*-
+\version "2.13.9"
%{
-Two functions define the chord repetition behavior, and may
+
+The following functions define the chord repetition behavior, and may
be invoked by the user to customize it.
ly:parser-set-repetition-symbol
`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.
+ is encountered by the parser: a four argument function
+ (previous-chord, location, 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)))
+#(define-public (default-repeat-chord previous-chord location duration articulations)
+ "Copy the previous chord, filter out events which are not notes, set
+the chord duration, add articulations."
+ ;; If previous-chord has an length property, then it means that it
+ ;; has been processed by a music iterator. In other words, the chord
+ ;; has been memorized in an other music block, which is certainly not
+ ;; what the user has intended. In that case, raise a warning.
+ (if (not (and (ly:music? previous-chord)
+ (null? (ly:music-property previous-chord 'length))))
+ (ly:input-message location
+ (_ "No memorized chord in music block before chord repetition")))
+ (let* ((new-chord (ly:music-deep-copy previous-chord))
+ (notes (filter (lambda (event)
+ (eqv? (ly:music-property event 'name) 'NoteEvent))
+ (ly:music-property new-chord 'elements))))
+ ;; remove possible cautionary/forced accidentals from notes
+ (for-each (lambda (note)
+ (if (eqv? (ly:music-property note 'cautionary) #t)
+ (set! (ly:music-property note 'cautionary) #f))
+ (if (eqv? (ly:music-property note 'force-accidental) #t)
+ (set! (ly:music-property note 'force-accidental) #f)))
+ notes)
+ ;; Add articulations and notes to the new event 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))))
+ (append! notes articulations))
+ ;; Set the duration of each event
(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))
+ ;; Set the new chord origin
+ (set! (ly:music-property new-chord 'origin) location)
+ ;; return the new chord
+ new-chord))
#(ly:parser-set-repetition-symbol parser 'q)
#(ly:parser-set-repetition-function parser default-repeat-chord)
For chord inversions, this is negative.")
(once ,boolean? "Apply this operation only during one time step?")
(origin ,ly:input-location? "Where was this piece of music defined?")
+ (original-chord ,ly:music? "Original chord of a repeated chord.
+Used by repeated chords in \\relative mode, to determine the first note octave")
(page-break-permission ,symbol? "When the music is at top-level,
whether to allow, forbid or force a page break.")
(types . (music-wrapper-music general-music relative-octave-music))
))
+ (RepeatedChord
+ . ((description . "A chord repetition")
+ (to-relative-callback . ,ly:music-sequence::repeated-chord-relative-callback)
+ (iterator-ctor . ,ly:music-wrapper-iterator::constructor)
+ (start-callback . ,ly:music-wrapper::start-callback)
+ (length-callback . ,ly:music-wrapper::length-callback)
+ (types . (general-music music-wrapper-music))
+ ))
+
(RepeatedMusic
. ((description . "Repeat music in different ways.")
(types . (general-music repeated-music))
'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))
+ (make-music 'RepeatedChord
+ 'original-chord previous-chord
+ 'element (repetition-function previous-chord location duration articulations)
+ 'origin location))
(define-ly-syntax-simple (context-specification type id mus ops create-new)
(let* ((type-sym (if (symbol? type) type (string->symbol type)))