On 2020-06-25 7:01 am, Maurits Lamers wrote:
Hi all,

I am trying to build a system based on the listener system which can
identify voices in a piece of music.
I use a listener to the Voice context to give me the note events.

In the following passage I can use (ly:context-id
(ly:translator-context engraver) to get the id, which is empty for c4,
"1" for the first voice, "2" for the second voice, and empty again for
d4 at the end.

time 4/4 \relative c' {  c4 << { c8 d e4 } \\ { c8 b c4 } >> d4 | }


However in the following passage the context-id cannot be used because
it is not set.

\relative c' {
      \new Voice {
        c4
        <<
          \new Voice {
            c8 d e4
          }
          \new Voice {
            c8 b c4
          }
        >>
        d4
      }
    }

I am currently using object properties to follow these voices by
setting a unique value for that voice context object, but that doesn't
help me
to detect properly the start and end of the polyphonic passage. The
main voice gets 1, the first nested voice will be 2, the second nested
voice will be 3.
For transcription purposes it would be very helpful to detect the
start and end of the polyphonic passage. Is this possible?

The initialize and finalize procedures of an engraver will run when the context in which it is \consisted begins and ends. Consider:

%%%%
\version "2.20.0"

#(define custom-uid
  (let ((custom-uid-prop (make-object-property))
        (last-uid 0))
    (lambda (obj)
      (or (custom-uid-prop obj)
          (begin
            (set! last-uid (1+ last-uid))
            (set! (custom-uid-prop obj) last-uid)
            last-uid)))))

handle-init-and-final =
#(lambda (context)
  (make-engraver
    ((initialize engraver)
      (let* ((ctxt (ly:translator-context engraver))
             (id (ly:context-id ctxt))
             (uid (custom-uid ctxt))
             (now (ly:context-now ctxt)))
        (format #t "\ninitialize: ~s, id=~s, uid=~s, now=~s"
          ctxt id uid now)))
    ((finalize engraver)
      (let* ((ctxt (ly:translator-context engraver))
             (id (ly:context-id ctxt))
             (uid (custom-uid ctxt))
             (now (ly:context-now ctxt)))
        (format #t "\nfinalize: ~s, id=~s, uid=~s, now=~s"
          ctxt id uid now)))))

\layout { \context { \Voice \consists \handle-init-and-final } }

{ \relative c' { \new Voice { c4
  << \new Voice = foo { \voiceOne c8 d e4 }
     \new Voice { \voiceTwo c8 b c4 } >> d4 } } }
%%%%

====
. . .
Parsing...
Interpreting music...
initialize: #<Context Voice () >, id="", uid=1, now=#<Mom -infinity>
initialize: #<Context Voice=foo () >, id="foo", uid=2, now=#<Mom 1/4>
initialize: #<Context Voice () >, id="", uid=3, now=#<Mom 1/4>
finalize: #<Context Voice=foo () >, id="foo", uid=2, now=#<Mom 3/4>
finalize: #<Context Voice () >, id="", uid=3, now=#<Mom 3/4>
finalize: #<Context Voice () >, id="", uid=1, now=#<Mom 1>
Preprocessing graphical objects...
. . .
====

NOTE: I am using Scheme object properties to attach a custom unique identifier to the contexts as they are seen, so it is possible to discern which context is which even when they are not named.


-- Aaron Hill

Reply via email to