2011/1/18 Jan-Peter Voigt <jp.vo...@gmx.de>: > Hello List, > > this is a very cool snippet! I also thought of trying this excersize ... > perhaps tomorrow ;-) > I think it should be posted to LSR! > There is one thing I tried: If you have markups in your lyrics: > > words = \lyricmode { This is my ex -- am -- ple \markup { \italic text } } > > this function will fail. > Perhaps someone is willing to play this scheme-game a bit further? >
Sure... You have to play the game, right? To allow markups, we have to use (markup #:concat ( . . )) instead of string-concatenate. The flatten-list function also has to be adjusted to leave the markups intact. There is no need to call flatten-list from inside the recursion in lyrics->list. It probably doesn't do any harm in this case, but I wonder if the original function (extract-named-music) is ever used on any `heavy' nested music structures, because if so, it might be a good idea to redefine it? (Theoretically, calling flatten-list from inside the recursion may result in N^2 calls to flatten-list when returning N elements from extract-named-music...) #(define (lyrics->list lyrics) "Return only syllables and hyphens from @code{lyrics}." (if (ly:music? lyrics) (if (memq (ly:music-property lyrics 'name) '(LyricEvent HyphenEvent)) (begin (if (eq? (ly:music-property lyrics 'name) 'LyricEvent) (list (ly:music-property lyrics 'text)) (list "--"))) (let ((elt (ly:music-property lyrics 'element)) (elts (ly:music-property lyrics 'elements))) (if (ly:music? elt) (lyrics->list elt) (if (null? elts) '() (map (lambda(x) (lyrics->list x)) elts))))) '())) #(define (flatten-nonmarkup-list x) "Unnest list, but don't flatten markup constructs!" (cond ((null? x) '()) ((not (pair? x)) (list x)) (else (append (if (markup? (car x)) (list (car x)) (flatten-nonmarkup-list (car x))) (flatten-nonmarkup-list (cdr x)))))) #(define (reduce-hyphens text) ;; Define initial first-word 'wd' and remaining-words 'wds' (let eat ((wd (car text)) (wds (cdr text))) (cond ;; Last syllable reached: Terminate recursion ((null? wds) (list wd)) ((and (equal? "--" (car wds)) (not (null? (cdr wds)))) ;; The next word is a hyphen AND there is a syllable after that hyphen ;; Concatenate the syllable after the hyphen onto wd, and recurse (eat (markup #:concat ((markup wd) (markup (cadr wds)))) (cddr wds))) ;; Not a hyphen, just use wd as the first word on the list, and then recurse. (else (cons wd (eat (car wds) (cdr wds))))))) #(define (lyrics->text lyrics) (reduce-hyphens (flatten-nonmarkup-list (lyrics->list lyrics)))) snip Jakob > Best regards, > Jan-Peter > > > On 18.01.2011 12:56, jakob lund wrote: >> >> 2011/1/18 Marc Hohl<m...@hohlart.de>: >>> >>> Am 15.01.2011 21:51, schrieb Neil Puttock: >>>> >>>> On 15 January 2011 19:01, Marc Hohl<m...@hohlart.de> wrote: >>>> >>>>> Now I wonder whether it is possible to create a kind of text book by >>>>> including the lyrics in a markup, perhaps with a scheme function which >>>>> replaces the " -- " by "". >>>>> >>>>> Is it possible to store the text in a variable? >>>> >>>> [...] >>>> >>>> For simplicity I've ignored hyphens, but it shouldn't be too difficult >>>> to add them (or use their position in the list of strings to restore >>>> the hyphenated words). >>> >>> This is what I got so far: >>> >>> \version "2.13.46" >>> >>> words = \lyricmode { This is my ex -- am -- ple text } >>> >>> #(define (lyrics->list lyrics) >>> "Return a flat list containing all syllables and hyphens from >>> @code{lyrics}." >>> (let ((extracted-list >>> (if (ly:music? lyrics) >>> (if (memq (ly:music-property lyrics 'name) '(LyricEvent >>> HyphenEvent)) >>> (begin (if (eq? (ly:music-property lyrics 'name) >>> 'LyricEvent) >>> (list (ly:music-property lyrics 'text)) >>> (list "--"))) >>> (let ((elt (ly:music-property lyrics 'element)) >>> (elts (ly:music-property lyrics 'elements))) >>> (if (ly:music? elt) >>> (lyrics->list elt) >>> (if (null? elts) >>> '() >>> (map (lambda(x) >>> (lyrics->list x)) >>> elts))))) >>> '()))) >>> (flatten-list extracted-list))) >>> >>> >>> text = #(lyrics->list words) >>> >>> melody = \relative c' { c4 d e f | g a c2 } >>> >>> \new Voice { \melody } >>> \addlyrics { \words } >>> >>> #(markup* (make-line-markup text)) >>> >>> The function liyrics->list extracts the syllables and the hyphens. >> >> Cool! >> >>> The second part (eliminating the hyphens in the list and concatenate the >>> surrounding >>> syllables) seems a bit harder, but I try to find a solution. >> >> That's a nice scheme exercise... The following would work (but not if >> there are consecutive hyphens) >> >> #(define (reduce-hyphens text) >> ;; Define initial first-word 'wd' and remaining-words 'wds' >> (let eat ((wd (car text)) (wds (cdr text))) >> (cond >> ;; Last syllable reached: Terminate recursion >> ((null? wds) (list wd)) >> ((and (equal? "--" (car wds)) (not (null? (cdr wds)))) >> ;; The first remaining word is a hyphen AND there >> is a syllable after that >> ;; Concatenate that syllable onto wd, and recurse >> (eat (string-concatenate (list wd (cadr wds))) (cddr >> wds))) >> ;; Not a hyphen, just use wd as the first word on >> the list, and then recurse. >> (else (cons wd (eat (car wds) (cdr wds))))))) >> >> #(define (lyrics->text lyrics) (reduce-hyphens (lyrics->list lyrics))) >> >> text = #(lyrics->text words) >> >> Cheers >> Jakob. >> >>> Regards, >>> >>> Marc >>> >>> _______________________________________________ >>> lilypond-user mailing list >>> lilypond-user@gnu.org >>> http://lists.gnu.org/mailman/listinfo/lilypond-user >>> >> _______________________________________________ >> lilypond-user mailing list >> lilypond-user@gnu.org >> http://lists.gnu.org/mailman/listinfo/lilypond-user >> > > > _______________________________________________ > lilypond-user mailing list > lilypond-user@gnu.org > http://lists.gnu.org/mailman/listinfo/lilypond-user > _______________________________________________ lilypond-user mailing list lilypond-user@gnu.org http://lists.gnu.org/mailman/listinfo/lilypond-user