Re: detecting the start and end of a polyphonic passage from scheme
Hi all, The way the staff is usually printed (through format and display) already gave me that idea, but it is good to see it confirmed. Let me try to sketch my problem and perhaps you could help me find an answer on how to achieve it. I am trying to find a way that I can serialize the voices and their content. The maximum size of the serialization block is a bar. Within this bar, I need to be able to order voices from low to high or the other way around. The polyphony in the serialization is indicated as either being full bar, partial bar or a combination of both. My technique currently is to use (par) and (seq) to indicate parallel or sequential structures. The example below would become something like this (par (seq g1) (seq g'8 e'8 (par (seq a'8. g'16 f'8 e'16 f' g' f' e' d') (seq c'8 a d'8. c'16 b8 a16 b or by only describing the voices: (par (seq "bottom") (seq "one" (par (seq "two") (seq "three")) ) The actual serialized output would then be (indicators between []) : g'8 e'8 [start partial polyphony] a'8. g'16 f'8 e'16 f' g' f' e' d' [simultaneous voice start] c'8 a d'8. c'16 b8 a16 b [start full measure polyphony] g1 From the structure above it is doable to get to this serialization as the initialization order because the order of events will be start of voice 1 start of voice 2 g'8 (voice 1) g1 (voice 2) e'8 (voice 1) start of voice 3 start of voice 4 This allows me to "anchor" the partial bar polyphony to voice 1 as it is the last note. I however realized that this approach is problematic in case the separation starts one eighth earlier, as it is no longer possible to find which voice is actually a partial bar polyphony or a whole bar. Any kind of hierarchical info on those voices would have helped me make the separation properly. As it obviously doesn't work this way, I need a different approach. I do see a solution which I saw before I took this approach, which is that I run rhythmically through the bar and "sort" the notes into the voices by keeping track of what sounds simultaneously. To be honest I have no clue how to do this. Moreover, there might be a better / easier way? Thanks in advance, cheers Maurits > Op 1 jul. 2020, om 11:34 heeft Aaron Hill het > volgende geschreven: > > On 2020-07-01 2:07 am, Maurits Lamers wrote: >> Follow up question: is there a way to know the "parent" of the voices >> as they are defined in the code? >> In the following example, I would like to determine that voice "two" >> splits off from voice "one" without relying on the context-id. >> (ly:context-parent ctx) gives me the staff, not the "parent voice"... >> [...] > > If I am not mistaken, Voices do not form a hierarchy with each other. The > parent context will always be some form of Staff. Consider: > > > \version "2.20.0" > > \new Voice = outer { e'8 g' \new Voice = inner { a'2 } b'4 } > > > LilyPond syntax might make it appear as if one Voice is "inside" another, but > that is an illusion. In reality, the two voices are in parallel with each > other. The inlining of the inner Voice here only serves to keep the outer > Voice alive. > > Here is an alternate way to view the above: > > > \version "2.20.0" > > { > \new Voice = outer { e'8 g' } > << >\context Voice = outer { s2 } >\new Voice = inner { a'2 } > >> > \context Voice = outer { b'4 } > } > > > Hopefully it is more clear that the two Voices are siblings, not parent-child. > > > -- Aaron Hill >
Re: detecting the start and end of a polyphonic passage from scheme
Am Mi., 1. Juli 2020 um 11:08 Uhr schrieb Maurits Lamers : > > Hi all, > > Follow up question: is there a way to know the "parent" of the voices as they > are defined in the code? > In the following example, I would like to determine that voice "two" splits > off from voice "one" without relying on the context-id. > (ly:context-parent ctx) gives me the staff, not the "parent voice"... > > \score { > \new Staff { > \time 2/2 > > << > \new Voice = "one" { > \relative c'' { > \voiceOne > g8 e > } > << > \new Voice = "two" { > \voiceOne > \relative c'' { a8. g16 f8 e16 f g f e d } > } > \new Voice = "three" { > \voiceTwo > \relative c' { c8 a d8. c16 b8 a16 b } > } > >> > } > \new Voice = bottom { > \voiceTwo > \relative c' { g1 } > } > >> > > } > } > > Thanks in advance! > Hi Maurits, I second Aaron, saying Voices are not parent of each other. Below some other code I once made. Not exactly what you need, maybe some addition to the fine code Aaron already provided, though. #(define (my-engraver ctx) (let ((new-contexts '())) `( (listeners (AnnounceNewContext . ,(lambda (engraver event) (set! new-contexts (cons event new-contexts) (finalize . ,(lambda (trans) (let ((ctx-type-id (map (lambda (c) (let ((creator (ly:event-property c 'creator))) (list (ly:event-property creator 'type) (ly:event-property creator 'id (delete-duplicates (reverse new-contexts) (format #t "\nInside this score ~a new contexts are created. Type and id are:\n~y" (length ctx-type-id) ctx-type-id) (set! ctx-type-id '() ))) #(define (single-context-parent-tree ctx) (if (and (ly:context? ctx) (ly:context? (ly:context-parent ctx))) (single-context-parent-tree (ly:context-parent ctx)) (format #f "~a" ctx))) printBottomContextParents = \context Bottom \applyContext #(lambda (a) (let ((ls (drop-right (string-split (single-context-parent-tree a) (car (string->list "("))) 1))) (format #t "\n\nThe Context-parent-tree:") (format #t "\n(Only contexts of type Global, Score, Staff and Voice are printed)") (for-each (lambda (s) (format #t "\n~a~a" (cond ((string-contains s "Score") (make-string 1 #\tab)) ((string-contains s "Staff") (make-string 2 #\tab)) ((string-contains s "Voice") (make-string 3 #\tab)) (else "")) (string-trim-both s (lambda (c) (or (eqv? c #\>) (eqv? c #\sp) (eqv? c #\))) ls))) \score { \new Staff { \time 2/2 << \new Voice = "one" { \relative c'' { \voiceOne g8 e } << \new Voice = "two" { \voiceOne \relative c'' { a8. g16 f8 e16 f g f e d } } \new Voice = "three" { \voiceTwo \relative c' { c8 a d8. c16 b8 a16 b } } >> } \new Voice = bottom { \voiceTwo \relative c' { g1 } } >> } \layout { \context { \Score \consists \my-engraver } \printBottomContextParents } } Cheers, Harm
Re: detecting the start and end of a polyphonic passage from scheme
On 2020-07-01 2:07 am, Maurits Lamers wrote: Follow up question: is there a way to know the "parent" of the voices as they are defined in the code? In the following example, I would like to determine that voice "two" splits off from voice "one" without relying on the context-id. (ly:context-parent ctx) gives me the staff, not the "parent voice"... [...] If I am not mistaken, Voices do not form a hierarchy with each other. The parent context will always be some form of Staff. Consider: \version "2.20.0" \new Voice = outer { e'8 g' \new Voice = inner { a'2 } b'4 } LilyPond syntax might make it appear as if one Voice is "inside" another, but that is an illusion. In reality, the two voices are in parallel with each other. The inlining of the inner Voice here only serves to keep the outer Voice alive. Here is an alternate way to view the above: \version "2.20.0" { \new Voice = outer { e'8 g' } << \context Voice = outer { s2 } \new Voice = inner { a'2 } >> \context Voice = outer { b'4 } } Hopefully it is more clear that the two Voices are siblings, not parent-child. -- Aaron Hill
Re: detecting the start and end of a polyphonic passage from scheme
Hi all, Follow up question: is there a way to know the "parent" of the voices as they are defined in the code? In the following example, I would like to determine that voice "two" splits off from voice "one" without relying on the context-id. (ly:context-parent ctx) gives me the staff, not the "parent voice"... \score { \new Staff { \time 2/2 << \new Voice = "one" { \relative c'' { \voiceOne g8 e } << \new Voice = "two" { \voiceOne \relative c'' { a8. g16 f8 e16 f g f e d } } \new Voice = "three" { \voiceTwo \relative c' { c8 a d8. c16 b8 a16 b } } >> } \new Voice = bottom { \voiceTwo \relative c' { g1 } } >> } } Thanks in advance! cheers Maurits > Van: Aaron Hill > Onderwerp: Antw.: detecting the start and end of a polyphonic passage from > scheme > Datum: 25 juni 2020 17:12:13 CEST > Aan: lilypond-user@gnu.org > > > 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: #, id="", uid=1, now=# > initialize: #, id="foo", uid=2, now=# > initialize: #, id="", uid=3, now=# > finalize: #, id="foo", uid=2, now=# > finalize: #, id="", uid=3, now=# > finalize: #, id="", uid=1, now=# > 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 > > > > > ___ > lilypond-user mailing list > lilypond-user@gnu.org > https://lists.gnu.org/mailman/listinfo/lilypond-user
Re: detecting the start and end of a polyphonic passage from scheme
Hi, Great solution, thanks a lot! cheers Maurits > 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: #, id="", uid=1, now=# > initialize: #, id="foo", uid=2, now=# > initialize: #, id="", uid=3, now=# > finalize: #, id="foo", uid=2, now=# > finalize: #, id="", uid=3, now=# > finalize: #, id="", uid=1, now=# > 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 > >
Re: detecting the start and end of a polyphonic passage from scheme
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: #, id="", uid=1, now=# initialize: #, id="foo", uid=2, now=# initialize: #, id="", uid=3, now=# finalize: #, id="foo", uid=2, now=# finalize: #, id="", uid=3, now=# finalize: #, id="", uid=1, now=# 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