gleiche Musikabschnitte finden (für Austausch von \voiceOne und \voiceTwo)

Begonnen von Arnold, Montag, 23. Juli 2018, 12:41

« vorheriges - nächstes »

Arnold

Hallo,

Ich schreibe häufig Stimmen ab und transponiere sie für (mehrere) Alternativinstrumente, dabei schreibe ich die Stichnoten wie im Beispiel unten. Häufig müssen dann (je nach Zielinstrument) \voiceOne und \voiceTwo ausgetauscht werden.
Kennt jemand eine effizientere Methode zum Vergleich zweiter ly:music-Objekte als diese in Lilypond-Strings umzuwandeln und die Zeichenketten zu vergleichen?

Natürlich soll diese Swap-Funktion später die zu bearbeitenden Bereiche nach Tags filtern, und auch noch die TextScript-Direction umschalten können.
\version "2.18.2"
swapVoicesOneTwo =
#(define-music-function (parser location mus) (ly:music?)
  (let* ((voiceOneMusic (ly:parser-lookup parser 'voiceOne))
         (voiceTwoMusic (ly:parser-lookup parser 'voiceTwo))
         (voiceOneDump (with-output-to-string (lambda () (display-lily-music voiceOneMusic parser))))
         (voiceTwoDump (with-output-to-string (lambda () (display-lily-music voiceTwoMusic parser)))))
   ; quick check to exclude most other music events:
   (define (may-be-voiceX mus)
    (let* ((name1 (if (ly:music? mus)
             (ly:music-property mus 'name)
             '()))
           (ctxtype1 (if (not (null? name1))
             (ly:music-property mus 'context-type)
             '()))
           (elem1 (if (and (not (null? name1))
                           (not (null? ctxtype1))
                           (eq? ctxtype1 'Voice)
                           (eq? name1 'ContextSpeccedMusic))
             (ly:music-property mus 'element)
             '()))
           (name2 (if (and (not (null? elem1))
                           (ly:music? elem1))
             (ly:music-property elem1 'name)
             '()))
           (len (if (and (not (null? name2))
                              (eq? name2 'SequentialMusic))
             (ly:music-length mus)
             '())))
     (and (ly:moment? len) (= (ly:moment-main len) 0))))
   ; mapping function compares 'display-lily-music' strings:
   (define (swap-voiceX mus)
    (if (may-be-voiceX mus)
     (let ((musDump (with-output-to-string (lambda () (display-lily-music mus parser)))))
      (if (string=? voiceOneDump musDump)
       (ly:music-deep-copy voiceTwoMusic)
       (if (string=? voiceTwoDump musDump)
        (ly:music-deep-copy voiceOneMusic)
        mus)))
     mus))
   ; call mapping:
   (music-map swap-voiceX mus)))

Musik = {
  c'1
  << { \voiceOne
    R1
  } \new CueVoice { \voiceTwo
    g'1
  } >> \oneVoice
  e'1
}

{ \clef treble \Musik }

\swapVoicesOneTwo { \clef alto \Musik }


Arnold

harm6

Hallo Anold,

was spricht gegen das simple


swapVoicesOneTwoII =
#(define-music-function (parser location mus) (ly:music?)
   (music-map
     (lambda (m)
       (cond ((equal? m #{ \voiceOne #})
                #{ \voiceTwo #})
             ((equal? m #{ \voiceTwo #})
                #{ \voiceOne #})
             (else m)))
     mus))


?


Gruß,
  Harm

Arnold

Hallo Harm,

ich habe wirklich nicht damit gerechnet, daß das »equal?« aus SCHEME die »origin«-Einträge aus der Lilypond-Struktur beim Vergleich unberücksichtigt läßt.

Danke, Arnold

harm6

Hallo Arnold,

ein Problem gibt es schon, denn:
#(format #t "\nvoiceOne-equality?: ~a" (equal?  #{ \voiceOne #} voiceOne))
returniert false.

Ich hab selber mal nachgefragt:
http://lilypond.1069038.n5.nabble.com/Iterating-music-for-voiceOne-Checking-with-equal-td215135.html

Mal sehen was dabei rauskommt.

Gruß,
  Harm

Arnold

Hallo Harm,

ich habe je eher vermutet, daß es mit #{ \voiceOne #} fehlschlägt (weil vermutlich eine Sequentielle-Musik herumgewickelt wird), aber #(parser-lookup 'voiceOne) funktioniert - aber laut meiner Versuche gibt equal? auch beim parser-lookup immer ein #f zurück.

Noch verwirrender für mich:
\version "2.19.82"
Get = #(define-music-function (sym) (symbol?)
(ly:parser-lookup sym))
GetVoiceOne = #(define-music-function () ()
#{ \voiceOne #} )

#(display "\n1. Test ******************************\n")
\displayMusic \voiceOne
#(display "\n2. Test ******************************\n")
\displayMusic \Get #'voiceOne
#(display "\n3. Test ******************************\n")
\displayMusic \GetVoiceOne

Alle displayMusic-Ergebnisse fangen mit (make-music 'ContextSpeccedMusic an.
Mir fällt aber gerade auf, daß im letzten noch zusätzlich ein Attribut-Werte-Paar 'length (ly:make-moment 0) in der obersten Ebene drinsteckt!

Arnold.

harm6

Hallo Arnold,

ich habe mal folgenden Test-Code versucht:


Get = #(define-music-function (sym) (symbol?)
(ly:parser-lookup sym))
GetVoiceOne = #(define-music-function () ()
#{ \voiceOne #} )


#(define tst-ls
  (list
    #{ \Get #'voiceOne #}
    (Get 'voiceOne)
    #{ \GetVoiceOne #}
    (GetVoiceOne)
    voiceOne
    #{ \voiceOne #}
    (ly:parser-lookup 'voiceOne)
    (ly:music-deep-copy voiceOne)
    (ly:music-deep-copy #{ \voiceOne #})
    (ly:music-deep-copy (ly:parser-lookup 'voiceOne))))

#(format #t "\ncleaned-list-length: ~a\n"
  (length (delete-duplicates tst-ls equal?)))


In 2.19.82 erhält man:
cleaned-list-length: 2

Ich hab' dann David Kastrups patch integriert, damit erhält man dann:
cleaned-list-length: 1

Mit dem von ihm vorgeschlagenen workaround
voiceOne = \voiceOne
returniert 2.19.82 ebenfalls
cleaned-list-length: 1

Insoweit haben wir einen workaround für jetzt, sowie einen patch für die Zukunft.
Ich denke das ist Problem ist soweit gelöst, wie es momentan geht.

Gruß,
  Harm

Arnold

Hallo Harm,

... und der zweite Workaround wäre mein Vergleich über display-lily-music.

Ob man vielleicht in Zukunft eine spezielle Vergleichsfunktion benötig, zu der man (als list-of-symbols) die zu ignorierenden Einträge angeben kann (z. Bsp. auch noch die tags) - wenn dann bestimmte Listen in der Reihenfolge, andere reihenfolgenunabhängig verglichen werden sollen, wirds noch aufwändiger.

Zur Zeit überlege ich noch, wie es bei dem (seltener von mir verwendeten) \cueDuring ausieht.
Abgesehen von einer Änderung der Richtung würde ich ja die Stichnoten einer Flöte in der Fagottstimme mittels \cueDuringWithClef im Violinschlüssel notieren, in der Baßklarinettenstimme aber mittels \transposedCueDuring.
Da muß ich mir erst einmal alle Kombinationen überlegen, welche zu erwarten sind. Und möglicherweise wäre es da dann besser, mit einem »neutralen benannten Cue-During-Platzhalter« in der Ursprungsstimme zu arbeiten, der dann erst bei der Bildung der Alternativstimme mit der passenden cueDuring-Variante ersetzt wird.

Arnold.