Re: custom engraver in scheme: accessing nested Music object
On Aug 10, Reinhold Kainhofer wrote: Am Mittwoch, 10. August 2011, 17:11:44 schrieb Ricardo Wurmus: On Aug 10, Neil Puttock wrote: BTW, if you're prepared to wrap the notes in a chord (so you have access to 'articulations), you won't even need a scheme engraver (all the processing can take place in the NoteHead's stencil callback). It should be a generic engraver, so I cannot assume that notes will always be wrapped in a chord. I'll play around with defining a function for process-acknowledged and see where it leads me. One detail that might be interesting for you is that you can define engraver- wide variables by wrapping the whole engraver in a (let (..) ...) block. See e.g. the scheme engraver instance regtest (input/regression/scheme- engraver-instance.ly in the source code tree): snip In this example, instance-counter is a global variable, which is reused by every voice, while instance-id and private-note-counter are variables that are separate for each voice. In this example, instance-id stores the number of the voice, while private-note-counter counts the number of notes in each voice separately. In particular, the engravers used in the first and in the second voice will have different private-note-counter variables. You can use this to collect information from all encountered objects and thin in 'process-acknowledged or 'stop-translation-timestep procell all of them at once. For a list of all possible functions inside the engraver, see input/regression/scheme-engraver.ly Thanks, this helped me quite a bit. The engraver is already working basically. Will just have to clean up and add a few more features. Cheers, Reinhold Best, Rekado ___ lilypond-devel mailing list lilypond-devel@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-devel
custom engraver in scheme: accessing nested Music object
Hello, I'm currently attempting to write a custom engraver in scheme. This is the shortened code: ;; global variables to be used in `do-something' #(define g_filled #f) #(define g_direction 0) #(define g_finger 0) #(define g_string-number 0) ;; #(define-public (music-cause grob) (let* ((event (event-cause grob))) (if (ly:stream-event? event) (ly:event-property event 'music-cause) #f))) #(define my-engraver (list (cons 'acknowledgers (list (cons 'note-head-interface (lambda (engraver grob source-engraver) (let* ((event (event-cause grob)) (mus (music-cause grob)) ;; TODO: how do I get *into* this articulations list? (articulations (ly:music-property mus 'articulations))) ;; note head filling depends on duration (set! g_filled (ly:moment? duration filled-threshold)) (do-something grob)) )) The `do-something' function (not shown here) replaces note heads according to variables that I hope to extract from the event data structure. In my code, the `mus' variable contains the music object, which has a property `articulations'. This is what the music object looks like when displaying it: #Prob: Music C++: Music( (length . #Mom 1/4) (elements) (duration . #Duration 4 ) (articulations #Prob: Stream_event C++: Stream_event ((music-cause . #Prob: Music C++: Music ((digit . 2) (origin . #location test.ly:50:14)) ((display-methods #procedure #f (event parser)) (name . FingeringEvent) (types general-music fingering-event event)) ) (digit . 2) (origin . #location test.ly:50:14)) ((class . fingering-event)) ) (pitch . #Pitch bes ) (origin . #location test.ly:50:11)) ((display-methods #procedure #f (note parser)) (name . NoteEvent) (types general-music event note-event rhythmic-event melodic-event)) I'm trying to get to the music object *inside* the `articulations' list, but I cannot seem to find a way to do so. Simply getting the property `articulations' with ly:music-property returns a list, but I cannot run cdr or car on that list to get to the Stream_event. Is there a way to do this? Maybe this is the wrong approach. Is there another way to get access to all music properties from within an acknowledger? Can I use more than one interface in the same acknowledger? I tried using event listeners before to collect the note properties, but this fails as soon as there is more than one voice, because the acknowledgers are called after *all* the listeners at a certain moment. I'd appreciate any comments or hints. Thanks, Rekado ___ lilypond-devel mailing list lilypond-devel@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-devel
Re: custom engraver in scheme: accessing nested Music object
Am Wednesday, 10. August 2011, 09:44:00 schrieb Ricardo Wurmus: Hello, I'm currently attempting to write a custom engraver in scheme. This is the shortened code: It will increase the chances for a useful answer dramatically if you could attach a working example that one just has to run through lilypond, rather than trying to read your code, trying to image how to use it, constructing the example myself and then try to figure out how to solve it. Cheers, Reinhold -- -- Reinhold Kainhofer, reinh...@kainhofer.com, http://reinhold.kainhofer.com/ * Financial Actuarial Math., Vienna Univ. of Technology, Austria * http://www.fam.tuwien.ac.at/, DVR: 0005886 * LilyPond, Music typesetting, http://www.lilypond.org ___ lilypond-devel mailing list lilypond-devel@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-devel
Re: custom engraver in scheme: accessing nested Music object
On Aug 10, Reinhold Kainhofer wrote: Am Wednesday, 10. August 2011, 09:44:00 schrieb Ricardo Wurmus: Hello, I'm currently attempting to write a custom engraver in scheme. This is the shortened code: It will increase the chances for a useful answer dramatically if you could attach a working example that one just has to run through lilypond, rather than trying to read your code, trying to image how to use it, constructing the example myself and then try to figure out how to solve it. I was trying to simplify it, because my scheme-foo is only a day old. But I guess you are right. Here is a working example of my engraver: https://github.com/rekado/Lilystick The engraver is in stick-tab-engraver.ly, a test file using the engraver is test.ly. Running `lilypond test.ly` will generate roughly what I want. This all fails, though, when more than one Voice is used. The reason for that is that I'm using event listeners to collect note properties and evaluate them in the acknowledger code. The listeners are executed first for all notes at a moment, and then the achnowledger code (stick-fingers grob) runs. Hence, the global variables (g_string-number, g_finger ...) are overwritten. To overcome this, I want to let the acknowledger grab note properties for each individual grob, instead of having the listeners grab them. Rekado ___ lilypond-devel mailing list lilypond-devel@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-devel
Re: custom engraver in scheme: accessing nested Music object
I have now spent ~25 minutes trying to strip down the engraver and adding what you had in your first mail, but I can't reproduce anything. The music-cause simply does not have any articulations here. So, I now wasted almost half an hour for what? Oh shoot, I confused my example scores. I just noticed that the articulations key (and the music-cause) only appears in the event list when there are simultaneous notes. This invalidates the approach (or rather workaround); anyway, I have attached a simple working example (articulations.ly) that generates the output I presented in my first email. I'm afraid it is not worth spending time on this anymore, now that the inadequacy of this procedure is established. I'm very sorry to have wasted your time. Your comments actually helped me to see how flawed my approach really is. Thank you for that. As I said above, I can't reproduce your claim that the music-cause has the articulations, so probably I did something different from what you had in mind (but didn't include it in your list). Please adjust the file to show your problem (and only your problem). In the future, this is the form that we would expect from you. So, if you really want us to spend precious time helping you, please make our life easier by sending really small, relevant examples. Noted and understood. Thanks for your patience. I think I will have to start from scratch (again). This is what I'm trying to do for each note in the score: 1. get the string number (string-number-interface) 2. get the finger info (finger-interface) 3. get the stem direction (stem-interface) 4. replace the note head dependent on 1-3 (note-head-interface) I tried to add acknowledgers for all these interfaces, but the function for the note-head-interface was always called *before* the others (see attached example ack-order.ly). Is there a way to change that order, or call the note-head-interface function again at the very end for processing a grob? I'm sure I'm missing something obvious here. (My ignorance even after reading the documentation for multiple times annoys me so much.) #(define-public (music-cause grob) (let* ((event (event-cause grob))) (if (ly:stream-event? event) (ly:event-property event 'music-cause) #f))) #(define stick-tab-engraver (list (cons 'acknowledgers (list (cons 'note-head-interface (lambda (engraver grob source-engraver) (let* ((context (ly:translator-context engraver)) (event (event-cause grob)) (mus (music-cause grob)) ;; get music object inside articulations ;; TODO: how do I get to the music-cause property in the Stream_event? (articulations (ly:music-property mus 'articulations))) ;; output articulations, so I can see how to ;; get to the music object inside. (display articulations)(newline) ;; replace the note head (do-something grob #(define (do-something grob) (display Not important\n)) % -- \version 2.14.2 \score { \time 2/4 \new Staff { \clef treble \key g \minor \new Voice { \relative c'' { d4-1\4 } } } \new Staff { \clef bass \key g \minor \new Voice { \relative g { % ugh, articulations only exist when % there are simultaneous notes d-2\4 g-4 } } } \layout { \context { \Staff \remove Fingering_engraver \consists \stick-tab-engraver } } } #(define stick-tab-engraver (list (cons 'acknowledgers (list (cons 'string-number-interface (lambda (engraver grob source-engraver) ;; TODO: get string-number info and store in var (display getting STRING info\n) )) (cons 'finger-interface (lambda (engraver grob source-engraver) ;; TODO: get fingering info and store in var (display getting FINGER info\n) )) (cons 'stem-interface (lambda (engraver grob source-engraver) ;; TODO: get stem direction info and store in var (display getting STEM info\n) )) (cons 'note-head-interface (lambda (engraver grob source-engraver) ;; TODO: replace the note head (do-something grob))) #(define (do-something grob) (display Replacing note head\n)) % -- \version 2.14.2 \score { \time 2/4 \new Staff { \clef treble \key g \minor
Re: custom engraver in scheme: accessing nested Music object
On 10 August 2011 15:00, Ricardo Wurmus ricardo.wur...@gmail.com wrote: Is there a way to change that order, or call the note-head-interface function again at the very end for processing a grob? Acknowledger order depends on the order engravers are \consist-ed (the only exception is if you set must-be-last to #t) If you want to do useful things to the NoteHead, you should wait until all the acknowledging has finished, i.e., store the NoteHead grob and process the information in a process-acknowledged or stop-translation-timestep function. BTW, if you're prepared to wrap the notes in a chord (so you have access to 'articulations), you won't even need a scheme engraver (all the processing can take place in the NoteHead's stencil callback). Cheers, Neil ___ lilypond-devel mailing list lilypond-devel@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-devel
Re: custom engraver in scheme: accessing nested Music object
On Aug 10, Neil Puttock wrote: On 10 August 2011 15:00, Ricardo Wurmus ricardo.wur...@gmail.com wrote: Is there a way to change that order, or call the note-head-interface function again at the very end for processing a grob? Acknowledger order depends on the order engravers are \consist-ed (the only exception is if you set must-be-last to #t) If you want to do useful things to the NoteHead, you should wait until all the acknowledging has finished, i.e., store the NoteHead grob and process the information in a process-acknowledged or stop-translation-timestep function. Thank you very much for the information. This is the bit I must have overlooked. BTW, if you're prepared to wrap the notes in a chord (so you have access to 'articulations), you won't even need a scheme engraver (all the processing can take place in the NoteHead's stencil callback). It should be a generic engraver, so I cannot assume that notes will always be wrapped in a chord. I'll play around with defining a function for process-acknowledged and see where it leads me. Cheers, Neil Best, Rekado ___ lilypond-devel mailing list lilypond-devel@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-devel
Re: custom engraver in scheme: accessing nested Music object
Am Mittwoch, 10. August 2011, 17:11:44 schrieb Ricardo Wurmus: On Aug 10, Neil Puttock wrote: BTW, if you're prepared to wrap the notes in a chord (so you have access to 'articulations), you won't even need a scheme engraver (all the processing can take place in the NoteHead's stencil callback). It should be a generic engraver, so I cannot assume that notes will always be wrapped in a chord. I'll play around with defining a function for process-acknowledged and see where it leads me. One detail that might be interesting for you is that you can define engraver- wide variables by wrapping the whole engraver in a (let (..) ...) block. See e.g. the scheme engraver instance regtest (input/regression/scheme- engraver-instance.ly in the source code tree): \header { texidoc = Scheme engravers may be instantiated, with instance-scoped slots, by defining a 1 argument procedure which shall return the engraver definition as an alist, with the private slots defined in a closure. The argument procedure argument is the context where the engraver is instantiated. } \version 2.14.0 \layout { \context { \Voice \consists #(let ((instance-counter 0)) (lambda (context) (set! instance-counter (1+ instance-counter)) (let ((instance-id instance-counter) (private-note-counter 0)) `((listeners (note-event . ,(lambda (engraver event) (set! private-note-counter (1+ private-note-counter)) (let ((text (ly:engraver-make-grob engraver 'TextScript event))) (ly:grob-set-property! text 'text (format #f ~a.~a instance-id private-note- counter)) } } \relative c'' { c4 d e f } \\ \relative c' { c4 d e f } In this example, instance-counter is a global variable, which is reused by every voice, while instance-id and private-note-counter are variables that are separate for each voice. In this example, instance-id stores the number of the voice, while private-note-counter counts the number of notes in each voice separately. In particular, the engravers used in the first and in the second voice will have different private-note-counter variables. You can use this to collect information from all encountered objects and thin in 'process-acknowledged or 'stop-translation-timestep procell all of them at once. For a list of all possible functions inside the engraver, see input/regression/scheme-engraver.ly Cheers, Reinhold -- -- Reinhold Kainhofer, reinh...@kainhofer.com, http://reinhold.kainhofer.com/ * Financial Actuarial Math., Vienna Univ. of Technology, Austria * http://www.fam.tuwien.ac.at/, DVR: 0005886 * LilyPond, Music typesetting, http://www.lilypond.org ___ lilypond-devel mailing list lilypond-devel@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-devel