Re: custom engraver in scheme: accessing nested Music object

2011-08-11 Thread Ricardo Wurmus
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

2011-08-10 Thread Ricardo Wurmus
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

2011-08-10 Thread Reinhold Kainhofer
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

2011-08-10 Thread Ricardo Wurmus
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

2011-08-10 Thread Ricardo Wurmus
 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

2011-08-10 Thread Neil Puttock
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

2011-08-10 Thread Ricardo Wurmus
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

2011-08-10 Thread Reinhold Kainhofer
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