summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--input/regression/display-lily-tests.ly2
-rw-r--r--lily/music-scheme.cc2
-rw-r--r--lily/parser.yy103
-rw-r--r--ly/music-functions-init.ly33
-rw-r--r--scm/define-music-display-methods.scm184
-rw-r--r--scm/modal-transforms.scm15
-rw-r--r--scm/music-functions.scm53
-rw-r--r--scm/song-util.scm17
-rw-r--r--scm/song.scm27
9 files changed, 213 insertions, 223 deletions
diff --git a/input/regression/display-lily-tests.ly b/input/regression/display-lily-tests.ly
index 998627b716..76bfc420c6 100644
--- a/input/regression/display-lily-tests.ly
+++ b/input/regression/display-lily-tests.ly
@@ -74,7 +74,7 @@ stderr of this run."
%% tags
\test ##[ { \tag #'foo { c4 d } } #]
-\test ##[ c-\tag #'foo -\tag #'baz -^ -. #]
+\test ##[ c-\tag #'foo -\tag #'baz -^-. #]
%% Graces
\test ##[ { \grace c8 d2 } #] % GraceMusic
diff --git a/lily/music-scheme.cc b/lily/music-scheme.cc
index 93fd55d9a5..ffa903b4eb 100644
--- a/lily/music-scheme.cc
+++ b/lily/music-scheme.cc
@@ -76,7 +76,7 @@ LY_DEFINE (ly_music_p, "ly:music?",
LY_DEFINE (ly_event_p, "ly:event?",
1, 0, 0, (SCM obj),
- "Is @var{obj} an event object?")
+ "Is @var{obj} a proper (non-rhythmic) event object?")
{
if (Music *m = unsmob_music (obj))
{
diff --git a/lily/parser.yy b/lily/parser.yy
index e59625cc36..e913d88cf1 100644
--- a/lily/parser.yy
+++ b/lily/parser.yy
@@ -201,7 +201,7 @@ while (0)
scm_apply_0 (proc, args)
/* Syntactic Sugar. */
#define MAKE_SYNTAX(name, location, ...) \
- LOWLEVEL_MAKE_SYNTAX (ly_lily_module_constant (name), scm_list_n (parser->self_scm (), make_input (location) , ##__VA_ARGS__, SCM_UNDEFINED));
+ LOWLEVEL_MAKE_SYNTAX (ly_lily_module_constant (name), scm_list_n (parser->self_scm (), make_input (location) , ##__VA_ARGS__, SCM_UNDEFINED))
#define START_MAKE_SYNTAX(name, ...) \
scm_list_n (ly_lily_module_constant (name) , ##__VA_ARGS__, SCM_UNDEFINED)
#define FINISH_MAKE_SYNTAX(start, location, ...) \
@@ -468,7 +468,6 @@ If we give names, Bison complains.
%type <scm> embedded_scm_bare
%type <scm> embedded_scm_bare_arg
%type <scm> embedded_scm_closed
-%type <scm> embedded_scm_chord_body
%type <scm> event_function_event
%type <scm> figure_list
%type <scm> figure_spec
@@ -513,7 +512,6 @@ If we give names, Bison complains.
%type <scm> multiplied_duration
%type <scm> music_function_event
%type <scm> music_function_chord_body
-%type <scm> music_function_chord_body_arglist
%type <scm> new_chord
%type <scm> new_lyrics
%type <scm> number_expression
@@ -776,16 +774,7 @@ identifier_init:
$$ = $1;
}
| music {
- /* Hack: Create event-chord around standalone events.
- Prevents the identifier from being interpreted as a post-event. */
- Music *mus = unsmob_music ($1);
- bool is_event = mus &&
- (scm_memq (ly_symbol2scm ("event"), mus->get_property ("types"))
- != SCM_BOOL_F);
- if (!is_event)
- $$ = $1;
- else
- $$ = MAKE_SYNTAX ("event-chord", @$, scm_list_1 ($1));
+ $$ = $1;
}
| post_event_nofinger {
$$ = $1;
@@ -2046,10 +2035,12 @@ scalar_closed:
event_chord:
- /* TODO: Create a special case that avoids the creation of
- EventChords around simple_elements that have no post_events?
- */
- simple_chord_elements post_events {
+ simple_element post_events {
+ // Let the rhythmic music iterator sort this mess out.
+ unsmob_music ($1)->set_property ("articulations",
+ scm_reverse_x ($2, SCM_EOL));
+ }
+ | simple_chord_elements post_events {
SCM elts = ly_append2 ($1, scm_reverse_x ($2, SCM_EOL));
Input i;
@@ -2111,7 +2102,8 @@ chord_body:
chord_body_elements:
/* empty */ { $$ = SCM_EOL; }
| chord_body_elements chord_body_element {
- $$ = scm_cons ($2, $1);
+ if (!SCM_UNBNDP ($2))
+ $$ = scm_cons ($2, $1);
}
;
@@ -2153,43 +2145,17 @@ chord_body_element:
$$ = n->unprotect ();
}
| music_function_chord_body
- ;
-
-/* We can't accept a music argument, not even a closed one,
- * immediately before chord_body_elements, otherwise a function \fun
- * with a signature of two music arguments can't be sorted out
- * properly in a construct like
- * <\fun { c } \fun { c } c>
- * The second call could be interpreted either as a chord constituent
- * or a music expression.
- */
-
-music_function_chord_body_arglist:
- function_arglist_bare
- | EXPECT_SCM music_function_chord_body_arglist embedded_scm_chord_body
{
- $$ = check_scheme_arg (parser, @3,
- $3, $2, $1);
- }
- ;
-
-embedded_scm_chord_body:
- embedded_scm_bare_arg
- | SCM_FUNCTION music_function_chord_body_arglist {
- $$ = MAKE_SYNTAX ("music-function", @$,
- $1, $2);
+ if (!unsmob_music ($$)->is_mus_type ("rhythmic-event")) {
+ parser->parser_error (@$, _ ("not a rhythmic event"));
+ $$ = SCM_UNDEFINED;
+ }
}
- | bare_number
- | fraction
- | lyric_element
- | chord_body_element
;
music_function_chord_body:
- MUSIC_FUNCTION music_function_chord_body_arglist {
- $$ = MAKE_SYNTAX ("music-function", @$,
- $1, $2);
- }
+ music_function_call
+ | MUSIC_IDENTIFIER
;
// Event functions may only take closed arglists, otherwise it would
@@ -2766,10 +2732,7 @@ simple_element:
;
simple_chord_elements:
- simple_element {
- $$ = scm_list_1 ($1);
- }
- | new_chord {
+ new_chord {
if (!parser->lexer_->is_chord_state ())
parser->parser_error (@1, _ ("have to be in Chord mode for chords"));
$$ = $1;
@@ -2795,35 +2758,29 @@ lyric_element:
lyric_element_arg:
lyric_element
| lyric_element multiplied_duration post_events {
- SCM lyric_event = MAKE_SYNTAX ("lyric-event", @$, $1, $2);
- $$ = MAKE_SYNTAX ("event-chord", @$,
- scm_cons (lyric_event,
- scm_reverse_x ($3, SCM_EOL)));
+ $$ = MAKE_SYNTAX ("lyric-event", @$, $1, $2);
+ unsmob_music ($$)->set_property
+ ("articulations", scm_reverse_x ($3, SCM_EOL));
}
| lyric_element post_event post_events {
- SCM lyric_event =
- MAKE_SYNTAX ("lyric-event", @$, $1,
- parser->default_duration_.smobbed_copy ());
- $$ = MAKE_SYNTAX ("event-chord", @$,
- scm_cons2 (lyric_event, $2,
- scm_reverse_x ($3, SCM_EOL)));
-
+ $$ = MAKE_SYNTAX ("lyric-event", @$, $1,
+ parser->default_duration_.smobbed_copy ());
+ unsmob_music ($$)->set_property
+ ("articulations", scm_cons ($2, scm_reverse_x ($3, SCM_EOL)));
}
| LYRIC_ELEMENT optional_notemode_duration post_events {
- SCM lyric_event = MAKE_SYNTAX ("lyric-event", @$, $1, $2);
- $$ = MAKE_SYNTAX ("event-chord", @$,
- scm_cons (lyric_event,
- scm_reverse_x ($3, SCM_EOL)));
+ $$ = MAKE_SYNTAX ("lyric-event", @$, $1, $2);
+ unsmob_music ($$)->set_property
+ ("articulations", scm_reverse_x ($3, SCM_EOL));
}
;
lyric_element_music:
lyric_element optional_notemode_duration post_events {
- SCM lyric_event = MAKE_SYNTAX ("lyric-event", @$, $1, $2);
- $$ = MAKE_SYNTAX ("event-chord", @$,
- scm_cons (lyric_event,
- scm_reverse_x ($3, SCM_EOL)));
+ $$ = MAKE_SYNTAX ("lyric-event", @$, $1, $2);
+ unsmob_music ($$)->set_property
+ ("articulations", scm_reverse_x ($3, SCM_EOL));
}
;
diff --git a/ly/music-functions-init.ly b/ly/music-functions-init.ly
index 9337127362..59c452065c 100644
--- a/ly/music-functions-init.ly
+++ b/ly/music-functions-init.ly
@@ -293,13 +293,11 @@ endSpanners =
#(define-music-function (parser location music) (ly:music?)
(_i "Terminate the next spanner prematurely after exactly one note
without the need of a specific end spanner.")
- (if (eq? (ly:music-property music 'name) 'EventChord)
- (let* ((elts (ly:music-property music 'elements))
- (start-span-evs (filter (lambda (ev)
- (and (music-has-type ev 'span-event)
- (equal? (ly:music-property ev 'span-direction)
- START)))
- elts))
+ (if (memq (ly:music-property music 'name) '(EventChord NoteEvent))
+ (let* ((start-span-evs (filter (lambda (ev)
+ (equal? (ly:music-property ev 'span-direction)
+ START))
+ (extract-typed-music music 'span-event)))
(stop-span-evs
(map (lambda (m)
(let ((c (music-clone m)))
@@ -314,7 +312,7 @@ without the need of a specific end spanner.")
total)
(begin
- (ly:input-message location (_ "argument endSpanners is not an EventChord: ~a" music))
+ (ly:input-message location (_ "argument endSpanners is not an EventChord: ~a") music)
music)))
@@ -325,16 +323,13 @@ featherDurations=
(let ((orig-duration (ly:music-length argument))
(multiplier (ly:make-moment 1 1)))
- (music-map
+ (for-each
(lambda (mus)
- (if (and (eq? (ly:music-property mus 'name) 'EventChord)
- (< 0 (ly:moment-main-denominator (ly:music-length mus))))
+ (if (< 0 (ly:moment-main-denominator (ly:music-length mus)))
(begin
(ly:music-compress mus multiplier)
- (set! multiplier (ly:moment-mul factor multiplier))))
- mus)
- argument)
-
+ (set! multiplier (ly:moment-mul factor multiplier)))))
+ (extract-named-music argument '(EventChord NoteEvent RestEvent SkipEvent)))
(ly:music-compress
argument
(ly:moment-div orig-duration (ly:music-length argument)))
@@ -846,13 +841,9 @@ pitchedTrill =
(_i "Print a trill with @var{main-note} as the main note of the trill and
print @var{secondary-note} as a stemless note head in parentheses.")
(let* ((get-notes (lambda (ev-chord)
- (filter
- (lambda (m) (eq? 'NoteEvent (ly:music-property m 'name)))
- (ly:music-property ev-chord 'elements))))
+ (extract-named-music ev-chord 'NoteEvent)))
(sec-note-events (get-notes secondary-note))
- (trill-events (filter (lambda (m) (music-has-type m 'trill-span-event))
- (ly:music-property main-note 'elements))))
-
+ (trill-events (extract-named-music main-note 'TrillSpanEvent)))
(if (pair? sec-note-events)
(begin
(let* ((trill-pitch (ly:music-property (car sec-note-events) 'pitch))
diff --git a/scm/define-music-display-methods.scm b/scm/define-music-display-methods.scm
index 4546afb0ac..ac9930e138 100644
--- a/scm/define-music-display-methods.scm
+++ b/scm/define-music-display-methods.scm
@@ -108,7 +108,9 @@ expression."
(define*-public (duration->lily-string ly-duration #:key (prev-duration (*previous-duration*))
(force-duration (*force-duration*))
(time-factor-numerator (*time-factor-numerator*))
- (time-factor-denominator (*time-factor-denominator*)))
+ (time-factor-denominator (*time-factor-denominator*))
+ remember)
+ (if remember (*previous-duration* ly-duration))
(let ((log2 (ly:duration-log ly-duration))
(dots (ly:duration-dot-count ly-duration))
(num+den (ly:duration-factor ly-duration)))
@@ -252,24 +254,22 @@ expression."
(and (with-music-match (?start (music
'SequentialMusic
elements ((music
- 'EventChord
- elements ((music
- 'SkipEvent
- duration (ly:make-duration 0 0 0 1))
- (music
- 'SlurEvent
- span-direction START))))))
- #t)
- (with-music-match (?stop (music
- 'SequentialMusic
- elements ((music
- 'EventChord
- elements ((music
- 'SkipEvent
- duration (ly:make-duration 0 0 0 1))
- (music
- 'SlurEvent
- span-direction STOP))))))
+ 'SkipEvent
+ duration (ly:make-duration 0 0 0 1)
+ articulations
+ ((music
+ 'SlurEvent
+ span-direction START))))))
+ #t)
+ (with-music-match (?stop (music
+ 'SequentialMusic
+ elements ((music
+ 'SkipEvent
+ duration (ly:make-duration 0 0 0 1)
+ articulations
+ ((music
+ 'SlurEvent
+ span-direction STOP))))))
(format #f "\\appoggiatura ~a" (music->lily-string ?music parser))))))
@@ -287,13 +287,12 @@ expression."
(and (with-music-match (?start (music
'SequentialMusic
elements ((music
- 'EventChord
- elements ((music
- 'SkipEvent
- duration (ly:make-duration 0 0 0 1))
- (music
- 'SlurEvent
- span-direction START)))
+ 'SkipEvent
+ duration (ly:make-duration 0 0 0 1)
+ articulations
+ ((music
+ 'SlurEvent
+ span-direction START)))
(music
'ContextSpeccedMusic
element (music
@@ -310,14 +309,14 @@ expression."
'RevertProperty
grob-property-path '(stroke-style)
symbol 'Flag))
+
(music
- 'EventChord
- elements ((music
- 'SkipEvent
- duration (ly:make-duration 0 0 0 1))
- (music
- 'SlurEvent
- span-direction STOP))))))
+ 'SkipEvent
+ duration (ly:make-duration 0 0 0 1)
+ articulations
+ ((music
+ 'SlurEvent
+ span-direction STOP))))))
(format #f "\\acciaccatura ~a" (music->lily-string ?music parser))))))
(define-extra-display-method GraceMusic (expr parser)
@@ -346,12 +345,16 @@ expression."
(*max-element-number-before-break*))))
(elements (ly:music-property seq 'elements))
(chord? (make-music-type-predicate 'EventChord))
+ (note-or-chord? (make-music-type-predicate 'EventChord 'NoteEvent
+ 'LyricEvent 'RestEvent
+ 'ClusterNoteEvent))
(cluster? (make-music-type-predicate 'ClusterNoteEvent))
(note? (make-music-type-predicate 'NoteEvent)))
(format #f "~a~a{~v%~v_~{~a~^ ~}~v%~v_}"
(if (any (lambda (e)
- (and (chord? e)
- (any cluster? (ly:music-property e 'elements))))
+ (or (cluster? e)
+ (and (chord? e)
+ (any cluster? (ly:music-property e 'elements)))))
elements)
"\\makeClusters "
"")
@@ -366,15 +369,17 @@ expression."
"\\figuremode ")
((any (lambda (chord)
(any (make-music-type-predicate 'LyricEvent)
- (ly:music-property chord 'elements)))
- (filter chord? elements))
+ (cons chord
+ (ly:music-property chord 'elements))))
+ (filter note-or-chord? elements))
"\\lyricmode ")
((any (lambda (chord)
(any (lambda (event)
(and (note? event)
(not (null? (ly:music-property event 'drum-type)))))
- (ly:music-property chord 'elements)))
- (filter chord? elements))
+ (cons chord
+ (ly:music-property chord 'elements))))
+ (filter note-or-chord? elements))
"\\drummode ")
(else ;; TODO: other modes?
""))
@@ -425,7 +430,7 @@ Otherwise, return #f."
(let* ((elements (ly:music-property chord 'elements))
(simple-elements (filter (make-music-type-predicate
'NoteEvent 'ClusterNoteEvent 'RestEvent
- 'MultiMeasureRestEvent 'SkipEvent 'LyricEvent)
+ 'SkipEvent 'LyricEvent)
elements)))
(if ((make-music-type-predicate 'StaffSpanEvent 'BreathingEvent) (car elements))
;; first, a special case: StaffSpanEvent (\startStaff, \stopStaff)
@@ -433,46 +438,39 @@ Otherwise, return #f."
(music->lily-string (car elements) parser)
(if (and (not (null? simple-elements))
(null? (cdr simple-elements))
- ;; special case: if this simple_element has any post_events in
- ;; its 'articulations list, it should be interpreted instead
- ;; as a note_chord_element to prevent spurious output, e.g.,
- ;; \displayLilyMusic < c-1\4 >8 -> c-1\48
- (null? (filter post-event?
- (ly:music-property (car simple-elements) 'articulations)))
+ ;; a non-empty articulation list is only possible with
+ ;; chord entry.
+ (null? (ly:music-property (car simple-elements) 'articulations))
;; same for simple_element with \tweak
(null? (ly:music-property (car simple-elements) 'tweaks)))
;; simple_element : note | figure | rest | mmrest | lyric_element | skip
(let* ((simple-element (car simple-elements))
- (duration (ly:music-property simple-element 'duration))
- (lily-string (format #f "~a~a~a~{~a~^ ~}"
- (music->lily-string simple-element parser)
- (duration->lily-string duration)
- (if (and ((make-music-type-predicate 'RestEvent) simple-element)
- (ly:pitch? (ly:music-property simple-element 'pitch)))
- "\\rest"
- "")
- (map-in-order (lambda (music)
- (music->lily-string music parser))
- (filter post-event? elements)))))
- (*previous-duration* duration)
- lily-string)
+ (duration (duration->lily-string
+ (ly:music-property simple-element 'duration)
+ #:remember #t)))
+ (format #f "~a~a~{~a~^ ~}"
+ (music->lily-string simple-element parser)
+ duration
+ (map-in-order (lambda (music)
+ (music->lily-string music parser))
+ (filter post-event? elements))))
(let ((chord-elements (filter (make-music-type-predicate
'NoteEvent 'ClusterNoteEvent 'BassFigureEvent)
elements))
(post-events (filter post-event? elements)))
(if (not (null? chord-elements))
;; note_chord_element : '<' (notepitch | drumpitch)* '>" duration post_events
- (let ((lily-string (format #f "< ~{~a ~}>~a~{~a~^ ~}"
- (map-in-order (lambda (music)
- (music->lily-string music parser))
- chord-elements)
- (duration->lily-string (ly:music-property (car chord-elements)
- 'duration))
- (map-in-order (lambda (music)
- (music->lily-string music parser))
- post-events))))
- (*previous-duration* (ly:music-property (car chord-elements) 'duration))
- lily-string)
+ (let* ((duration (duration->lily-string
+ (ly:music-property (car chord-elements) 'duration)
+ #:remember #t)))
+ (format #f "< ~{~a ~}>~a~{~a~^ ~}"
+ (map-in-order (lambda (music)
+ (music->lily-string music parser))
+ chord-elements)
+ duration
+ (map-in-order (lambda (music)
+ (music->lily-string music parser))
+ post-events)))
;; command_element
(format #f "~{~a~^ ~}" (map-in-order (lambda (music)
(music->lily-string music parser))
@@ -499,7 +497,7 @@ Otherwise, return #f."
;;;
(define (simple-note->lily-string event parser)
- (format #f "~a~a~a~a~{~a~}" ; pitchname octave !? octave-check articulations
+ (format #f "~a~a~a~a~a~a~{~a~}" ; pitchname octave !? octave-check duration optional_rest articulations
(note-name->lily-string (ly:music-property event 'pitch) parser)
(octave->lily-string (ly:music-property event 'pitch))
(let ((forced (ly:music-property event 'force-accidental))
@@ -519,6 +517,10 @@ Otherwise, return #f."
(make-string (1- (* -1 octave-check)) #\,))
(else "")))
""))
+ (duration->lily-string (ly:music-property event 'duration)
+ #:remember #t)
+ (if ((make-music-type-predicate 'RestEvent) event)
+ "\\rest" "")
(map-in-order (lambda (event)
(music->lily-string event parser))
(ly:music-property event 'articulations))))
@@ -527,7 +529,9 @@ Otherwise, return #f."
(cond ((not (null? (ly:music-property note 'pitch))) ;; note
(simple-note->lily-string note parser))
((not (null? (ly:music-property note 'drum-type))) ;; drum
- (format #f "~a" (ly:music-property note 'drum-type)))
+ (format #f "~a~a" (ly:music-property note 'drum-type)
+ (duration->lily-string (ly:music-property note 'duration)
+ #:remember #t)))
(else ;; unknown?
"")))
@@ -537,13 +541,16 @@ Otherwise, return #f."
(define-display-method RestEvent (rest parser)
(if (not (null? (ly:music-property rest 'pitch)))
(simple-note->lily-string rest parser)
- "r"))
+ (string-append "r" (duration->lily-string (ly:music-property rest 'duration)
+ #:remember #t))))
(define-display-method MultiMeasureRestEvent (rest parser)
- "R")
+ (string-append "R" (duration->lily-string (ly:music-property rest 'duration)
+ #:remember #t)))
(define-display-method SkipEvent (rest parser)
- "s")
+ (string-append "s" (duration->lily-string (ly:music-property rest 'duration)
+ #:remember #t)))
(define-display-method RepeatedChord (chord parser)
(music->lily-string (ly:music-property chord 'element) parser))
@@ -615,18 +622,21 @@ Otherwise, return #f."
(if (null? bracket-stop) "" "]"))))
(define-display-method LyricEvent (lyric parser)
- (let ((text (ly:music-property lyric 'text)))
- (if (or (string? text)
- (eqv? (first text) simple-markup))
- ;; a string or a simple markup
- (let ((string (if (string? text)
- text
- (second text))))
- (if (string-match "(\"| |[0-9])" string)
- ;; TODO check exactly in which cases double quotes should be used
- (format #f "~s" string)
- string))
- (markup->lily-string text))))
+ (format "~a~{~a~^ ~}"
+ (let ((text (ly:music-property lyric 'text)))
+ (if (or (string? text)
+ (eqv? (first text) simple-markup))
+ ;; a string or a simple markup
+ (let ((string (if (string? text)
+ text
+ (second text))))
+ (if (string-match "(\"| |[0-9])" string)
+ ;; TODO check exactly in which cases double quotes should be used
+ (format #f "~s" string)
+ string))
+ (markup->lily-string text)))
+ (map-in-order (lambda (m) (music->lily-string m parser))
+ (ly:music-property lyric 'articulations))))
(define-display-method BreathingEvent (event parser)
"\\breathe")
diff --git a/scm/modal-transforms.scm b/scm/modal-transforms.scm
index 737d7e2a9f..9617329d77 100644
--- a/scm/modal-transforms.scm
+++ b/scm/modal-transforms.scm
@@ -126,7 +126,7 @@ LilyPond scheme pitches, e.g. @code{(ly:make-pitch 0 2 0)}
(change-pitches element converter)))))
-(define (extract-pitch-sequence music)
+(define (make-scale music)
"Recurse through @var{music}, extracting pitches.
Returns a list of pitch objects, e.g
@code{'((ly:make-pitch 0 2 0) (ly:make-pitch 0 4 0) ... )}
@@ -140,20 +140,15 @@ Typically used to construct a scale for input to transposer-factory
(cond
((ly:pitch? pitch)
- pitch)
+ (list pitch))
((pair? elements)
- (map
- (lambda (x) (extract-pitch-sequence x))
+ (append-map
+ (lambda (x) (make-scale x))
elements))
((ly:music? element)
- (extract-pitch-sequence element)))))
-
-(define (make-scale music)
- "Convenience wrapper for extract-pitch-sequence."
- (map car (extract-pitch-sequence music)))
-
+ (make-scale element)))))
(define (make-extended-scale music)
"Extend scale given by @var{music} by 5 octaves up and down."
diff --git a/scm/music-functions.scm b/scm/music-functions.scm
index 1b1d07c490..6114e144d6 100644
--- a/scm/music-functions.scm
+++ b/scm/music-functions.scm
@@ -276,12 +276,12 @@ through MUSIC."
(set! (ly:music-property r 'repeat-count) (max times 1))
(set! (ly:music-property r 'elements) talts)
(if (and (equal? name "tremolo")
- (or (pair? (ly:music-property main 'elements))
- (ly:music? (ly:music-property main 'element))))
+ (pair? (extract-named-music main 'NoteEvent)))
;; This works for single-note and multi-note tremolos!
(let* ((children (if (music-is-of-type? main 'sequential-music)
;; \repeat tremolo n { ... }
- (length (extract-named-music main 'EventChord))
+ (length (extract-named-music main '(EventChord
+ NoteEvent)))
;; \repeat tremolo n c4
1))
;; # of dots is equal to the 1 in bitwise representation (minus 1)!
@@ -311,7 +311,7 @@ if durations in @var{music} vary, allowing slash beats and double-percent
beats to be distinguished."
(let* ((durs (map (lambda (elt)
(duration-of-note elt))
- (extract-named-music music 'EventChord)))
+ (extract-named-music music '(EventChord NoteEvent))))
(first-dur (car durs)))
(if (every (lambda (d) (equal? d first-dur)) durs)
@@ -1517,7 +1517,8 @@ Entries that conform with the current key signature are not invalidated."
(define-public (duration-of-note event-chord)
(let ((evs (filter (lambda (x)
(music-has-type x 'rhythmic-event))
- (ly:music-property event-chord 'elements))))
+ (cons event-chord
+ (ly:music-property event-chord 'elements)))))
(and (pair? evs)
(ly:music-property (car evs) 'duration))))
@@ -1526,21 +1527,33 @@ Entries that conform with the current key signature are not invalidated."
(define-public (extract-named-music music music-name)
"Return a flat list of all music named @var{music-name} from @var{music}."
- (let ((extracted-list
- (if (ly:music? music)
- (if (eq? (ly:music-property music 'name) music-name)
- (list music)
- (let ((elt (ly:music-property music 'element))
- (elts (ly:music-property music 'elements)))
- (if (ly:music? elt)
- (extract-named-music elt music-name)
- (if (null? elts)
- '()
- (map (lambda(x)
- (extract-named-music x music-name ))
- elts)))))
- '())))
- (flatten-list extracted-list)))
+ (if (not (list? music-name))
+ (set! music-name (list music-name)))
+ (if (ly:music? music)
+ (if (memq (ly:music-property music 'name) music-name)
+ (list music)
+ (let ((arts (ly:music-property music 'articulations)))
+ (append-map!
+ (lambda (x) (extract-named-music x music-name))
+ (if (pair? arts)
+ arts
+ (cons (ly:music-property music 'element)
+ (ly:music-property music 'elements))))))
+ '()))
+
+(define-public (extract-typed-music music type)
+ "Return a flat list of all music with @var{type} from @var{music}."
+ (if (ly:music? music)
+ (if (music-is-of-type? music type)
+ (list music)
+ (let ((arts (ly:music-property music 'articulations)))
+ (append-map!
+ (lambda (x) (extract-typed-music x type))
+ (if (pair? arts)
+ arts
+ (cons (ly:music-property music 'element)
+ (ly:music-property music 'elements))))))
+ '()))
(define-public (event-chord-notes event-chord)
"Return a list of all notes from @var{event-chord}."
diff --git a/scm/song-util.scm b/scm/song-util.scm
index 9a65d44c8e..568b967ba6 100644
--- a/scm/song-util.scm
+++ b/scm/song-util.scm
@@ -159,7 +159,9 @@ If it unsets the property, return @code{#f}."
(define-public (music-elements music)
"Return list of all @var{music}'s top-level children."
(let ((elt (ly:music-property music 'element))
- (elts (ly:music-property music 'elements)))
+ (elts (append
+ (ly:music-property music 'articulations)
+ (ly:music-property music 'elements))))
(if (not (null? elt))
(cons elt elts)
elts)))
@@ -182,12 +184,17 @@ If it unsets the property, return @code{#f}."
(define-public (process-music music function)
"Process all nodes of @var{music} (including @var{music}) in the DFS order.
Apply @var{function} on each of the nodes. If @var{function} applied on a
-node returns @code{#t}, don't process the node's subtree."
+node returns @code{#t}, don't process the node's subtree.
+
+If a non-boolean is returned, it is considered the material to recurse."
(define (process-music queue)
(if (not (null? queue))
(let* ((elt (car queue))
(stop (function elt)))
- (process-music (if stop
- (cdr queue)
- (append (music-elements elt) (cdr queue)))))))
+ (process-music (if (boolean? stop)
+ (if stop
+ (cdr queue)
+ (append (music-elements elt) (cdr queue)))
+ ((if (cheap-list? stop) append cons)
+ stop (cdr queue)))))))
(process-music (list music)))
diff --git a/scm/song.scm b/scm/song.scm
index ffa53816c2..71eb03d72f 100644
--- a/scm/song.scm
+++ b/scm/song.scm
@@ -214,7 +214,7 @@
(lambda (music)
(cond
;; true lyrics
- ((music-name? music 'EventChord)
+ ((music-name? music '(EventChord LyricEvent))
(let ((lyric-event (find-child-named music 'LyricEvent)))
(push! (make-lyrics
#:text (ly:music-property lyric-event 'text)
@@ -374,7 +374,21 @@
(append (score-notes-note/rest-list last-result)
(list rest-spec)))
(add! (make-score-notes #:note/rest-list (list rest-spec)) result-list))))))
- #f)
+ (filter
+ (lambda (m)
+ (not (music-name? m '(RestEvent
+ NoteEvent
+ LyricEvent
+ MultiMeasureRestEvent))))
+ (ly:music-property music 'elements)))
+ ((music-name? music '(RestEvent
+ NoteEvent
+ LyricEvent
+ MultiMeasureRestEvent))
+ (make-music 'EventChord
+ 'elements
+ (cons music
+ (ly:music-property music 'articulations))))
;; autobeaming change
((music-property? music 'autoBeaming)
(set! autobeaming (property-value music))
@@ -384,10 +398,12 @@
(let ((change (if (property-value music) 1 -1)))
(set! in-slur (+ in-slur change))
(if last-note-spec
- (set-note-joined! last-note-spec (+ (note-joined last-note-spec) change)))))
+ (set-note-joined! last-note-spec (+ (note-joined last-note-spec) change))))
+ #t)
;; tempo change
((music-property? music 'tempoWholesPerMinute)
- (set! *tempo-compression* (ly:moment-div *default-tempo* (property-value music))))
+ (set! *tempo-compression* (ly:moment-div *default-tempo* (property-value music)))
+ #t)
;; breathe
((music-name? music 'BreathingEvent)
(if last-note-spec
@@ -396,7 +412,8 @@
#:origin (ly:music-property music 'origin))))
(set-note-duration! last-note-spec (* note-duration (*breathe-shortage*)))
(add! (make-score-notes #:note/rest-list (list rest-spec)) result-list))
- (warning music "\\\\breathe without previous note known")))
+ (warning music "\\\\breathe without previous note known"))
+ #t)
;; anything else
(else
#f))))