|
From: | Jan-Peter Voigt |
Subject: | Re: templates and a little bit more |
Date: | Tue, 10 Apr 2012 13:52:45 +0200 |
User-agent: | Mozilla/5.0 (X11; Linux i686; rv:11.0) Gecko/20120327 Thunderbird/11.0.1 |
On 06.04.2012 13:17, Janek Warchoł wrote:
Yes, my template mechanism has a similar intention. And I think OrchestraLily is a great tool.On Thu, Apr 5, 2012 at 7:37 PM, Jan-Peter Voigt <address@hidden> wrote:Dear community, I bundled some extensions in a little package to try out. Some of these ideas might be interesting to include in lily. Here is a start of some docs, but just a little bit. I am working on it ... http://www.xn--schne-noten-tfb.de/?tabs=3,1I'm sorry that i don't have time to dig deeper, but my first impression is that it's somewhat similar to OrchestralLily: http://lac.linuxaudio.org/2010/papers/25.pdf http://reinhold.kainhofer.com/orchestrallily/A-simple-example.html#A-simple-example - it may give you some inspiration. But here are two points I wanted to solve differently: 1.: Orchestralily uses "normal" lilypond-variables to store and organize the music. An advantage is a quite simple input. But a question, I had and read several times on this list remains, why and how to deal with the strict naming rules for lily-vars. So I started storing music in scheme variables, to be able to use vars with a name verse1. Then I thought about the tree-like structure of music - Reinhold Kainhofer made a nice figure about this in his paper. 2.: I want to use normal music-functions for templates, so anything that fits in a music template, fits in a template. The JSON-like template syntax for oly is not my taste ;-) The music is stored in a hash-tree-structure, wich uses a goops-class "tree" (found in lascm.scm): --snip-- ; ... (define-class <tree> () (children #:accessor children #:init-thunk make-hash-table) (key #:accessor key #:init-keyword #:key #:init-value 'node) (value #:accessor value #:setter set-value! #:init-value #f) ) (define-method (tree-set! (tree <tree>) (path <list>) val) (if (= (length path) 0) (set! (value tree) val) (let* ((ckey (car path)) (cpath (cdr path)) (child (hash-ref (children tree) ckey)) ) (if (not (is-a? child <tree>)) (begin (set! child (make <tree> #:key ckey)) (hash-set! (children tree) ckey child) )) (tree-set! child cpath val) )) val) ; ... (define-method (tree-get-tree (tree <tree>) (path <list>)) (if (= (length path) 0) tree (let* ((ckey (car path)) (cpath (cdr path)) (child (hash-ref (children tree) ckey)) ) (if (is-a? child <tree>) (tree-get-tree child cpath) #f) ))) (define-method (tree-get (tree <tree>) (path <list>)) (let ((ctree (tree-get-tree tree path))) (if (is-a? ctree <tree>) (value ctree) #f))) ; ... --snip-- Hidden in a module '(lalily store) is a tree, to which music is stored with the \putMusic command. Also there is a "current music folder" var - I call it folder, because the term context is already reserved in lily, and this tree forms a file-system-like structure: \getMusic resolves the music stored in the tree in the given path relative to the current folder. A template is music-function with a defined signature also stored in a tree: \registerTemplate #'(generic) #(define-music-function (parser location piece options)(list? list?) ; location parameter for error messages, if music is not found (get-music piece location)) This tree-like structure allows several music pieces side by side. A collection of songs might lead to a tree: chor/alta-trinita/music/sop chor/alta-trinita/text/sop chor/alta-trinita/music/alt chor/alta-trinita/text/alt ... chor/horianna/music/sop chor/hosianna/text/sop ... Then, when calling a template for satb-choral music, you give paths '(chor alta-trinita) and '(chor hosianna). This will fetch the music from the store as needed. If a template is called with \callTemplate, the current folder and the current template are set accordingly on a path-stack and reset when the template-function returns. So writing a template means writing a scheme-function. That is not simplifying input in the first place. And storing music means using a scheme-list as a path. This also is not simplifying the input - in the first shot. But it divides input in storing music and calling a template. This is an advantage for automation and it simplifies input, if one can input scheme-values, which are used in several places in lily (e.g. pairs in markup-overrides). And a template can loop over the music - I use this in the "choral-lied" templates to create a Lyrics-context for each verse. Writing a template may get confusing, but if a template needed is at hand, typesetting music can be reduced almost to input the notes. For a music folder, a template to use can be stored. A template can call another template relative to its own path, so if you have a template '(lead-sheet), it might recursively call a template '(lead-sheet lyrics). I also implemented some functions to automate the creation of the actual scores. The one I use most times is \lalilyTest, wich creates a bookpart with \layout- and \midi-block only if parser-output matches the file referenced in location. So Output is only generated if I compile the file directly. If this file is included in another file, the "music store" is filled, but no output is generated. So to test the input, I work directly on this file, to generate a publication, I might use another file, including all music needed and generating scores and bookparts without midi. There may also be more informations stored for a specific 'music-folder' like title, layout or paper, which will be used, when generating a score or bookpart. My template-collection is not a complete set, but it can be easily extented for your own needs, if you are able to define a music-function. ...Generally speaking, i'd very much linke to simplify writing LilyPond scores. Have you read my article "LilyPond's future"? (http://news.lilynet.net/?The-LilyPond-Report-25&lang=en#lilypond_s_future) ... I think, you will need one or two infos more, to distinguish the multiple appearances of tenors. But if you have a template #'(choral tenor), you can call it and call it accordingly. --snip-- \version "2.15.36" \include "lalily.ly" % if you have a template (this is not a simplification) \registerTemplate #'(choral tenor) #(define-music-function (parser location piece options)(list? list?) #{ << \new Staff = "tenor" \with { \consists Ambitus_engraver } { \clef "G_8" \set Staff.instrumentName = "Tenor" \set Staff.shortInstrumentName = "T" \set Staff.midiInstrument = "Choir Aahs" \autoBeamOff \dynamicUp \new Voice = "tenor" \getMusic #'(music tenor) } \new Lyrics \lyricsto "tenor" \getMusic #'(text tenor) >> #}) % you can use it in these few lines (I think this is a simplification, if one looses the fear regarding '#') \setDefaultTemplate #'(my music) #'(choral tenor) #'() \setTitle "My Music" \putMusic #'(music tenor) \relative c' { bes4 a c b } \putMusic #'(text tenor) \lyricmode { B A C H } \lalilyTest --snip-- The template might be found in either a file templates./myown/.ly in the lalily folder of this bundle or a file lalily-templates.ly in the current directory. In the current templates.ly file are found: #'(generic) returns the music found at the current path #'(NOTFOUND) like generic, but also outputs a warning - used, when template not found #'(transpose) transpose the music, returned by named template - used by \setTransposedTemplate pitch-from pitch-to #'(music path) #'(template path) #'(options) #'(lead-sheet) create lead-sheet uses: #'(meta) #'(chords) #'(global) #'(melody) #'(lyrics /verse/) #'(lead-sheet lyrics) called by #'(lead-sheet) #'(choral group) create a choir staff with staffs named in options (default is satb) #'(choral group staff lyrics) create one choral staff with lyrics - called by #'(choral group) These expect music #'(noten voc) and #'(text voc) The structure of the piece is defined in #'(meta) Before each voice #'(global) is included #'(choral lied staff) staff part #'(choral lied staff lyrics) lyrics part #'(choral lied satb4) layout music in 4 staves #'(choral lied satb2) layout music in 2 staves with lyrics in the middle #'(choral lied satb2b) layout music in 2 staves with lyrics under each stave These #'(choral lied) templates look for #'(noten /sop|alt|ten|bas/) and #'(text /verse/) The options given need to be a list and most times are an a-list. For example here a transposed one: --snip-- \version "2.15.36" \include "lalily.ly" % options in an a-list, containing an a-list \setTransposedTemplate c' bes #'(my music) #'(choral group) #'((staffs . ( (sop . ((inst . "Sopran") (sinst . "S"))) (alt . ((inst . "Alt") (sinst . "A"))) (ten . ((clef . "G_8") (inst . "Tenor") (sinst . "T"))) (bas . ((clef . "bass") (inst . "Bass") (sinst . "B"))) ))) \putMusic #'(meta) { \key c \major \time 4/4 s1 \override StaffGroup.SpanBar #'transparent = ##f \bar "|." } \putMusic #'(global) { \autoBeamOff \dynamicUp } \putMusic #'(noten sop) \relative c'' { c4 } \putMusic #'(text sop) \lyricmode { do } \putMusic #'(noten alt) \relative c'' { g4 } \putMusic #'(text alt) \lyricmode { di } \putMusic #'(noten ten) \relative c' { e4 } \putMusic #'(text ten) \lyricmode { da } \putMusic #'(noten bas) \relative c { c4 } \putMusic #'(text bas) \lyricmode { dum } \lalilyTest --snip-- To make the options not to weird ... an a-list containing a-lists ... not nice and not *easy* ... there is a command \setOption: \setOption #'staffs #'( (sop . ((inst . "Sopran") (sinst . "S"))) (alt . ((inst . "Alt") (sinst . "A"))) (ten . ((clef . "G_8") (inst . "Tenor") (sinst . "T"))) (bas . ((clef . "bass") (inst . "Bass") (sinst . "B"))) ) Still there is list-thing to write - that is not nice. So I will probably rewrite the command \setOption #'(/path/) Ok, enough for now ... so much to say about this, but only, if there is anyone interested (Janek, you have to do your exams and GSoC - so I don't expect you digging deep ;-) ) Cheers, Jan-Peter |
[Prev in Thread] | Current Thread | [Next in Thread] |