--- /dev/null
+\version "2.19.14"
+
+\header {
+ texidoc = "
+@code{\\addlyrics} may get used on a @code{Staff} context and will
+then consider all note events created below it for synchronization.
+"
+}
+
+\relative \new Staff {
+ \time 2/4
+ c''4 b8. a16 g4.
+ << { r8 a4( b) c2 } \\
+ { f,8 e4 d c2 }
+ >>
+}
+\addlyrics {
+ Life is __ _ love, _ live __ _ life.
+}
+\addlyrics {
+ No more let sins and sor -- rows grow.
+}
bool
melisma_busy (Context *tr)
{
- SCM melisma_properties = tr->get_property ("melismaBusyProperties");
- bool busy = false;
+ // When there are subcontexts, they are responsible for maintaining
+ // melismata.
+ SCM ch = tr->children_contexts ();
+ if (scm_is_pair (ch))
+ {
+ // all contexts need to have a busy melisma for this to evaluate
+ // to true.
+
+ do {
+ if (!melisma_busy (Context::unsmob (scm_car (ch))))
+ return false;
+ ch = scm_cdr (ch);
+ } while (scm_is_pair (ch));
+ return true;
+ }
- for (; !busy && scm_is_pair (melisma_properties);
+ for (SCM melisma_properties = tr->get_property ("melismaBusyProperties");
+ scm_is_pair (melisma_properties);
melisma_properties = scm_cdr (melisma_properties))
- busy = busy || to_boolean (tr->get_property (scm_car (melisma_properties)));
+ if (to_boolean (tr->get_property (scm_car (melisma_properties))))
+ return true;
- return busy;
+ return false;
}
bool
Context *lyrics_context_;
Context *music_context_;
SCM lyricsto_voice_name_;
+ SCM lyricsto_voice_type_;
Moment busy_moment_;
Moment pending_grace_moment_;
music_context_ = 0;
lyrics_context_ = 0;
busy_moment_.set_infinite (-1);
+ lyricsto_voice_name_ = SCM_UNDEFINED;
+ lyricsto_voice_type_ = SCM_UNDEFINED;
}
/*
{
if (music_context_)
{
- music_context_->event_source ()->
+ music_context_->events_below ()->
remove_listener (GET_LISTENER (set_busy), ly_symbol2scm ("rhythmic-event"));
}
music_context_ = to;
if (to)
{
- to->event_source ()->add_listener (GET_LISTENER (set_busy),
+ to->events_below ()->add_listener (GET_LISTENER (set_busy),
ly_symbol2scm ("rhythmic-event"));
}
}
scm_gc_mark (lyrics_context_->self_scm ());
if (music_context_)
scm_gc_mark (music_context_->self_scm ());
+ scm_gc_mark (lyricsto_voice_name_);
+ scm_gc_mark (lyricsto_voice_type_);
}
void
}
lyricsto_voice_name_ = get_music ()->get_property ("associated-context");
+ lyricsto_voice_type_ = get_music ()->get_property ("associated-context-type");
+ if (!scm_is_symbol (lyricsto_voice_type_))
+ lyricsto_voice_type_ = ly_symbol2scm ("Voice");
Context *voice = find_voice ();
if (voice)
SCM running = lyrics_context_
? lyrics_context_->get_property ("associatedVoice")
: SCM_EOL;
-
- if (scm_is_string (running))
+ SCM voice_type = lyricsto_voice_type_;
+ if (scm_is_string (running)) {
voice_name = running;
+ voice_type = lyrics_context_->get_property ("associatedVoiceType");
+ }
if (scm_is_string (voice_name)
- && (!music_context_ || ly_scm2string (voice_name) != music_context_->id_string ()))
+ && (!music_context_ || ly_scm2string (voice_name) != music_context_->id_string ())
+ && scm_is_symbol (voice_type))
{
Context *t = get_outlet ();
while (t && t->get_parent_context ())
t = t->get_parent_context ();
string name = ly_scm2string (voice_name);
- return find_context_below (t, ly_symbol2scm ("Voice"), name);
+ return find_context_below (t, voice_type, name);
}
return 0;
if (!music_found_)
{
SCM voice_name = get_music ()->get_property ("associated-context");
-
- string name;
+ SCM voice_type = get_music ()->get_property ("associated-context-type");
+ string name, type;
if (scm_is_string (voice_name))
name = ly_scm2string (voice_name);
+ type = robust_symbol2string (voice_type, "Voice");
/* Don't print a warning for empty lyrics (in which case we don't try
to find the proper voice, so it will not be found) */
if (lyrics_found_)
- get_music ()->origin ()->warning (_f ("cannot find Voice `%s'",
- name.c_str ()) + "\n");
+ get_music ()->origin ()->warning (_f ("cannot find %s `%s'",
+ type.c_str (), name.c_str ()) + "\n");
}
if (lyric_iter_)
nm = nm.substr (0, idx);
}
+ SCM voice_type = lyrics->get_property ("associatedVoiceType");
+ if (!scm_is_symbol (voice_type))
+ return 0;
+
Context *parent = lyrics;
Context *voice = 0;
while (parent && !voice)
{
- voice = find_context_below (parent, ly_symbol2scm ("Voice"), nm);
+ voice = find_context_below (parent, voice_type, nm);
parent = parent->get_parent_context ();
}
voice = 0;
while (parent && !voice)
{
- voice = find_context_below (parent, ly_symbol2scm ("Voice"), "");
+ voice = find_context_below (parent, voice_type, "");
parent = parent->get_parent_context ();
}
| repeated_music
| music_bare
| LYRICSTO simple_string lyric_mode_music {
- $$ = MAKE_SYNTAX ("lyric-combine", @$, $2, $3);
+ $$ = MAKE_SYNTAX ("lyric-combine", @$, $2, SCM_EOL, $3);
+ }
+ | LYRICSTO symbol '=' simple_string lyric_mode_music
+ {
+ $$ = MAKE_SYNTAX ("lyric_combine", @$, $3, $2, $4);
}
;
drumStyleTable = #drums-style
+ associatedVoiceType = #'Voice
melismaBusyProperties = #default-melisma-properties
tieWaitForNote = ##f
clefGlyph = #"clefs.G"
(alternativeRestores ,symbol-list? "Timing variables that are
restored to their value at the end of the first alternative in
subsequent alternatives.")
- (associatedVoice ,string? "Name of the @code{Voice} that has the
+ (associatedVoice ,string? "Name of the context (see
+@code{associatedVoiceType} for its type, usually @code{Voice}) that
+has the melody for this @code{Lyrics} line.")
+ (associatedVoiceType ,symbol? "Type of the context that has the
melody for this @code{Lyrics} line.")
(autoAccidentals ,list? "List of different ways to typeset an
accidental.
TODO: Consider making type into symbol.")
(articulations ,ly:music-list?
"Articulation events specifically for this note.")
- (associated-context ,string? "Name of the Voice context associated with
+ (associated-context ,string? "Name of the context associated with
+this @code{\\lyricsto} section.")
+ (associated-context-type ,symbol? "Type of the context associated with
this @code{\\lyricsto} section.")
(augmented ,boolean? "This figure is for an augmented figured
bass (with @code{+} sign).")
'context-type ctx
'origin location)))
-(define (get-first-context-id! type mus)
- "Find the name of a ContextSpeccedMusic with given type, possibly naming it"
+(define (get-first-context-id! mus)
+ "Find the name of a ContextSpeccedMusic, possibly naming it"
(let ((id (ly:music-property mus 'context-id)))
- (if (and (eq? (ly:music-property mus 'name) 'ContextSpeccedMusic)
- (eq? (ly:music-property mus 'context-type) type))
+ (if (eq? (ly:music-property mus 'name) 'ContextSpeccedMusic)
(if (and (string? id)
(not (string-null? id)))
id
(define-ly-syntax-simple (lyric-event text duration)
(make-lyric-event text duration))
-(define (lyric-combine-music sync music loc)
+(define (lyric-combine-music sync sync-type music loc)
;; CompletizeExtenderEvent is added following the last lyric in MUSIC
;; to signal to the Extender_engraver that any pending extender should
;; be completed if the lyrics end before the associated voice.
(make-music 'LyricCombineMusic
'element music
'associated-context sync
+ 'associated-context-type sync-type
'origin loc))
-(define-ly-syntax (lyric-combine parser location voice music)
- (lyric-combine-music voice music location))
+(define-ly-syntax (lyric-combine parser location voice typ music)
+ (lyric-combine-music voice typ music location))
(define-ly-syntax (add-lyrics parser location music addlyrics-list)
- (let* ((existing-voice-name (get-first-context-id! 'Voice music))
+ (let* ((existing-voice-name (get-first-context-id! music))
(voice-name (if (string? existing-voice-name)
existing-voice-name
(get-next-unique-voice-name)))
(voice (if (string? existing-voice-name)
music
- (if (eq? (ly:music-property music 'name) 'ContextSpeccedMusic)
- (begin
- (set! (ly:music-property music 'element)
- (make-music 'ContextSpeccedMusic
- 'element (ly:music-property music 'element)
- 'context-type 'Voice
- 'context-id voice-name
- 'origin (ly:music-property music 'origin)))
- music)
- (make-music 'ContextSpeccedMusic
- 'element music
- 'context-type 'Voice
- 'context-id voice-name
- 'origin (ly:music-property music 'origin)))))
+ (make-music 'ContextSpeccedMusic
+ 'element music
+ 'context-type 'Voice
+ 'context-id voice-name
+ 'origin (ly:music-property music 'origin))))
+ (voice-type (ly:music-property voice 'context-type))
(lyricstos (map (lambda (mus)
(let* ((loc (ly:music-property mus 'origin))
- (lyr (lyric-combine-music voice-name mus loc)))
+ (lyr (lyric-combine-music
+ voice-name voice-type mus loc)))
(make-music 'ContextSpeccedMusic
'create-new #t
'context-type 'Lyrics