Autor Thema: Probleme mit Scheme/LilyPond-Interna/relative  (Gelesen 1919 mal)

fugenkomponist

  • Member
Probleme mit Scheme/LilyPond-Interna/relative
« am: Mittwoch, 7. August 2013, 17:35 »
Hallo,

ich hab beschlossen, mir mal ein bisschen scheme anzueignen. Das erste kleine Projekt ist eine coll’ottava-Funktion. Das klappt für den Anfang auch erstaunlich gut, ich bin aber auf mehrere Probleme gestoßen:
• Ich laufe rekursiv in die ganzen SequentialMusic, TimeScaledMusic etc. rein, bis ich auf EventChords oder NoteEvents stoße. Die meisten Eigenschaften (z. B. bei TimeScaledMusic nominator und denominator und bei NoteEvents duration, pitch, tweaks) will ich übernehmen und nur element/elements und articulations ändern. Nun weiß ich aber
    * erstens nicht, welche das alle sind (und wo ich das rauskriegen könnte) und
    * zweitens frage ich mich, ob das nicht auch einfacher geht, nach dem Motto „gib das ursprüngliche Objekt zurück, nur mit der articulations-Eigenschaft geändert“ statt „baue ein neues Objekt, das diese und jene Eigenschaften vom alten übernimmt und die und die articulations besitzt“. Scheme ist ja nicht rein funktional, deshalb könnte ich mir vorstellen, dass das irgendwie geht, oder?
• \relative bereitet mir Probleme: wenn ich \relative c' { \collottavaMusic { <c e> g' } } sage, baue ich mir im Moment daraus im Prinzip \relative c' { <c c' e e'> <g' g''> } statt dem eigentlich gewollten \relative c' { <c c' e, e'> <g' g'> }. Irgendwie hab ich keine Ahnung, wo ich da ansetzen könnte.

Hat jemand Ahnung von Scheme/LilyPond-Interna und könnte mir ein, zwei Hinweise dazu geben?

Viele Grüße,
Malte

Ach ja, zum Notenbeispiel noch: das ist nur für mich gewesen, um zu sehen, dass ich weder Artikulationen dupliziere noch verliere (aber Ties, die wohl den Artikulationen zugerechnet werden, sollen ja doch verdoppelt werden) etc. Aber man sieht am zweiten Beispiel (ganz unten im Code) ganz gut, dass es mit \relative noch nicht so tut wie mit absoluten Tonhöhen (erstes Beispiel, eigentlich sollten die beiden identisch sein).
\version "2.16.0"

#(define (octave-up note)
   (make-music
    'NoteEvent
    'articulations (ly:music-property note 'articulations)
    'tweaks (ly:music-property note 'tweaks)
    'duration (ly:music-property note 'duration)
    'pitch (ly:pitch-transpose
            (ly:music-property note 'pitch)
            (ly:make-pitch 1 0 0))))

#(define (without-articulations note)
   (make-music
    'NoteEvent
    'articulations (filter
                    (lambda (e)
                      (eq?
                       (ly:music-property e 'name)
                       'TieEvent))
                    (ly:music-property note 'articulations))
    'tweaks (ly:music-property note 'tweaks)
    'duration (ly:music-property note 'duration)
    'pitch (ly:music-property note 'pitch)))

#(define (eventchord-from-noteevent note)
   (make-music
    'EventChord
    'articulations (ly:music-property note 'articulations)
    'elements (list
               (without-articulations note)
               (octave-up (without-articulations note)))))

#(define (eventchord-from-eventchord chord)
   (make-music
    'EventChord
    'elements
    (fold-right
      append
      '()
      (map
       (lambda (note)
         (if
          (eq? (ly:music-property note 'name) 'NoteEvent)
          (list
           (without-articulations note)
           (octave-up (without-articulations note)))
          (list note)))
       (ly:music-property chord 'elements)))))
   
#(define (collottava music)
   (cond
    ((eq? (ly:music-property music 'name) 'NoteEvent)
     (eventchord-from-noteevent music))
    ((eq? (ly:music-property music 'name) 'EventChord)
     (eventchord-from-eventchord music))
    ((not (eq? (ly:music-property music 'elements) '()))
     (make-music
      (ly:music-property music 'name)
      'elements (map collottava (ly:music-property music 'elements))))
    ((not (eq? (ly:music-property music 'element) '()))
     (make-music
      (ly:music-property music 'name)
      'numerator (ly:music-property music 'numerator)
      'denominator (ly:music-property music 'denominator)
      'element (collottava (ly:music-property music 'element))))
    (else music)))

collottavaMusic =
#(define-music-function
  (parser location music)
  (ly:music?)
  (collottava music))

\displayMusic { c'
  \collottavaMusic {
    <d' f'>4\f <d'~ f'>-.
    <\tweak #'font-size #-3 d' f'> d'2\glissando es'8-.( fis'\f
    \times 2/3 { a8 b c' }
  } g'4)
}

\displayMusic {
  \relative c' {
    c
    \collottavaMusic {
      <d f>4\f <d~ f>-.
      <\tweak #'font-size #-3 d f> d2\glissando es8-.( fis\f
      \times 2/3 { a,8 b c }
    }
    g'4)
  }
}
« Letzte Änderung: Mittwoch, 7. August 2013, 17:40 von fugenkomponist »

fugenkomponist

  • Member
Re: Probleme mit Scheme/LilyPond-Interna/relative
« Antwort #1 am: Mittwoch, 7. August 2013, 21:17 »
    * zweitens frage ich mich, ob das nicht auch einfacher geht, nach dem Motto „gib das ursprüngliche Objekt zurück, nur mit der articulations-Eigenschaft geändert“ statt „baue ein neues Objekt, das diese und jene Eigenschaften vom alten übernimmt und die und die articulations besitzt“. Scheme ist ja nicht rein funktional, deshalb könnte ich mir vorstellen, dass das irgendwie geht, oder?
Hm, Snippet 266 http://lsr.dsi.unimi.it/LSR/Item?id=266 macht was mit set! und ly:music-set-property!, ich glaub, da kann ich mir mal Anregung holen.

Edit: was ich noch bräuchte, wäre dann eine Möglichkeit, ein NoteEvent zu duplizieren; bisher brauchte ich das ja nicht, weil ich pro Ton zwei neue NoteEvents angelegt habe, von denen eins aber nen anderen pitch hatte … Es scheint aber nicht so, als gäbs eine generische Kopierfunktion in Scheme.

Alternativ würde mir auch ein Mechanismus helfen, mit dem ich über alle music-properties laufen kann, ohne sie einzeln zu nennen.

Edit: Zwischenstand mit music-set-property!:
\version "2.16.0"

#(define (octave-up note)
   (ly:music-set-property!
    note
    'pitch
    (ly:pitch-transpose
     (ly:music-property note 'pitch)
     (ly:make-pitch 1 0 0)))
   note)

#(define (without-articulations note)
   (ly:music-set-property!
    note
    'articulations
    (filter
     (lambda (event)
       (eq?
        (ly:music-property event 'name)
        'TieEvent))
     (ly:music-property note 'articulations)))
   note)

#(define (eventchord-from-noteevent note)
   (make-music
    'EventChord
    'articulations (ly:music-property note 'articulations)
    'elements (list
               (without-articulations note)
               (octave-up (without-articulations note)))))

#(define (modify-eventchord chord)
   (ly:music-set-property!
    chord
    'elements   
    (fold-right
      append
      '()
      (map
       (lambda (note)
         (if
          (eq? (ly:music-property note 'name) 'NoteEvent)
          (list
           (without-articulations note)
           (octave-up (without-articulations note)))
          (list note)))
       (ly:music-property chord 'elements))))
   chord)
   
#(define (collottava music)
   (cond
    ((eq? (ly:music-property music 'name) 'NoteEvent)
     (eventchord-from-noteevent music))
    ((eq? (ly:music-property music 'name) 'EventChord)
     (modify-eventchord music))
    ((pair? (ly:music-property music 'elements))
     (ly:music-set-property!
      music
      'elements
      (map collottava (ly:music-property music 'elements)))
     music)
    ((ly:music? (ly:music-property music 'element))
     (ly:music-set-property!
      music
      'element
      (collottava (ly:music-property music 'element)))
     music)
    (else music)))

collottavaMusic =
#(define-music-function
  (parser location music)
  (ly:music?)
  (collottava music))

\collottavaMusic {
  \relative c' {
    c d e f
  }
}
« Letzte Änderung: Mittwoch, 7. August 2013, 22:20 von fugenkomponist »

fugenkomponist

  • Member
Re: Probleme mit Scheme/LilyPond-Interna/relative
« Antwort #2 am: Mittwoch, 7. August 2013, 23:13 »
Ich hab was gefunden: So was gibts schon, aber in deutlich kürzer: http://lsr.dsi.unimi.it/LSR/Item?id=445 Allerdings hab ich gerade gesehn, dass da einzelne Noten auch als EventChords angesehn werden, was sie wohl in 2.16.0 nicht mehr sind (da funktioniert das Snippet nur noch halb); diese Fallunterscheidung konnte man sich damals wohl sparen.
ly:music-deep-copy heißt das Zauberwort. Und in Snippet 538 hab ich noch eine Funktion namens music-map gefunden, der Name klingt so, als könnte die auch ab und zu ganz hilfreich sein. Gibts denn irgendwo eine Dokumentation dafür? (Kann grad nicht schauen, obs vielleicht in der IR steht, weil ich keine lokale Kopie hab und lilypond.org down ist)

Edit: hab das debian/Ubuntu-Paket lilypond-doc gefunden, music-deep-copy steht in der IR auch kurz erwähnt drin, music-map aber nicht … aber es steht in scm/music-functions.scm drin. Schade, dass das nirgendwo (?) dokumentiert ist, teilweise ist das Zeug ja recht nützlich.
« Letzte Änderung: Donnerstag, 8. August 2013, 07:31 von fugenkomponist »

Arnold

  • Member
Re: Probleme mit Scheme/LilyPond-Interna/relative
« Antwort #3 am: Donnerstag, 8. August 2013, 09:27 »
Hallo,

es gibt sowohl eine Lilypond-Variante \musicmap proc music als auch eine Scheme-Variante (music-map proc music).
Beide haben zwei Aufrufparameter:
a) eine Scheme-Funktion mit ly:music? als Eingangsparameter und auch wieder eine ly:music? als Rückgabewert
b) die zu bearbeitende Musik
Als Ergebnis kommt die (gesamte) bearbeitete Musik zurück.

music-map ruft die mitgegebene Funktion rekursiv »von unten nach oben« für jedes ly:music?-Element auf.
Also bei \repeat volta 2 { \transpose { a' b' }  } \alternative { { c' } { d' } } grob in folgender Reihenfolge (ohne EventChord und NoteEvent)
  I = "Sequential Music" { a' b' }
  II = \transpose \I
  III = "Sequential Music" { c' }
  IV = "Sequential Music" { d' }
  V = "Repeated Music" body-element = \II 1st-volta = \III 2nd-volta = \IV

Der typische erste Prozessschritt in der Anwender-Scheme-Funktion, welche dem Music-Map übergeben wird, ist herauszufinden, was für ein Music-Event es ist.
Der typische erste Schritt bei der Entwicklung einer solchen Funktion ist meist, am Bildschirm aufzulisten welches MusicEvent übergeben wurde, und das Original zurückzugeben.

In meiner stradella-toolbox für die Stradella-Bass-Notation des Akkordeons (Sektion "Notenspezifisch - Noten für Akkordeon, Ziehharmonika") findest du einige Beispiele. Auch "articulate.ly" benutzt die music-map Funktion. Mit dieser Funktionalität wird für den "Stradella-Bass" schrittweise die Musik von der "Stellvertreter-Notation" (absolute Oktave x, = Grundton, absolute Oktave x = Dur-Dreiklang, x' = Moll-Dreiklang, x'' = Septakkord, ...) in die echten Noten für den Baßschlüssel umgewandelt, bis zum Schluß den letzten Rest ein Scheme-Engraver erledigt.

A propos: Darauf achten, daß in der Scheme-Variante oft ein music-deep-copy nötig wird.

Arnold