Deutschsprachiges LilyPond-Forum

Allgemeine Fragen und Probleme => Fragen und Probleme aller Art => Thema gestartet von: Manuela am Montag, 24. Februar 2020, 17:43

Titel: Mehrere bookparts in einer Funktion ausgeben - geht das? ---> gelöst
Beitrag von: Manuela am Montag, 24. Februar 2020, 17:43
Hi,
ich möchte mehrere bookparts in einer Ausgabe zusammenfassen, nachfolgend ein (nicht funktionierendes) Beispiel:
\version "2.19.83"

test =
#(define-music-function (p)
   (ly:pitch?)
   #{
     \new Staff \transpose c $p \relative c'' { c e g }
   #}
   )

xtest =
#(define-void-function (p q) (ly:pitch? ly:pitch?)
   (add-score
    (scorify-music #{ { \test $p } #}))
   (add-score
    (scorify-music #{ { \test $q } #}))
   )

mybook =
#(define-void-function (p) (ly:pitch?)
   #{
     \bookpart {
       \xtest $p $p
     }
     \bookpart {
       \xtest $p $p
     }
   #}
   )

\book {
  \mybook c
}


Wenn ich in die Funktion mybook nur einen bookpart einfüge, erhalte ich zwar keine Fehlermeldung, aber auch keine Ausgabe.

Lilypond bricht mit einer Fehlermeldung unexpected \bookpart, expecting end of input ab.

Kann man das Programm so ändern, dass es funktioniert?
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: harm6 am Montag, 24. Februar 2020, 18:18

\version "2.19.83"

test =
#(define-music-function (p)
   (ly:pitch?)
   #{
     \new Staff \transpose c $p \relative c'' { cis e g }
   #})

xtest =
#(define-scheme-function (p q) (ly:pitch? ly:pitch?)
  (scorify-music (test p)))

mybook =
#(define-void-function (p) (ly:pitch?)
  (let* ((bk (ly:make-book $defaultpaper $defaultheader '()))
         (bk-parts
           (list
             (ly:make-book-part (list (xtest p p)))
             (ly:make-book-part (list (xtest p p))))))

    (for-each
      (lambda (bookpart) (ly:book-add-bookpart! bk bookpart))
      bk-parts)
 
    (ly:book-process
      bk
      $defaultpaper
      $defaultlayout
      (ly:parser-output-name))))

\mybook c


Sollte Dich in die richtige Richtung bringen.
Auch wenn der Beispiel-Code arg abgespeckt ist, Z.B. xtest hat zwei Variablen, verwendet aber nur eine.


Gruß,
  Harm
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: Manuela am Montag, 24. Februar 2020, 20:55
Danke Harm. Das ist sehr hilfreich für mich  :)

Der Beispielcode ist natürlich grober Unfug, mein tatsächlicher Code ist ein wenig sinnvoller ;-)
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: Manuela am Dienstag, 25. Februar 2020, 18:04
Hallo Harm,
leider klappt es nicht wie gewünscht. Z.B. ist nicht jeder bookpart auf einer eigenen Seite.

Wahrscheinlich ist mein Code wieder mal zu kompliziert.  :( :-[
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: Manuela am Dienstag, 25. Februar 2020, 18:15
Ich habe rausgefunden, woran es liegt. Sobald in der define-scheme-function addscore 2x auftaucht, tuscht es. Hier ein Beispiel:
\version "2.19.83"

test =
#(define-music-function (p)
   (ly:pitch?)
   #{
     \new Staff \transpose c $p \relative c'' { cis e g }
   #})

xtest =
#(define-scheme-function (p q) (ly:pitch? ly:pitch?)
   (add-score
    (scorify-music (test p)))
   (add-score
    (scorify-music (test q)))
   )

mybook =
#(define-void-function (p q) (ly:pitch? ly:pitch?)
   (let* ((bk (ly:make-book $defaultpaper $defaultheader '()))
          (bk-parts
           (list
            (ly:make-book-part (list (xtest p q)))
            (ly:make-book-part (list (xtest q p))))))

     (for-each
      (lambda (bookpart) (ly:book-add-bookpart! bk bookpart))
      bk-parts)

     (ly:book-process
      bk
      $defaultpaper
      $defaultlayout
      (ly:parser-output-name))))

\mybook c d
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: harm6 am Dienstag, 25. Februar 2020, 18:30
ZitatIch habe rausgefunden, woran es liegt. Sobald in der define-scheme-function addscore 2x auftaucht, tuscht es

Nun, warum überhaupt add-score?
In meinem Beipiel hatte ich es gestrichen, sodaß xtest einen score zurückgibt! Wozu mehr?

Gruß,
  Harm
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: Manuela am Dienstag, 25. Februar 2020, 18:42
Danke für deine Antworten, Harm.

Weil ich eine Überschrift als markup habe, und das markup kriege ich in keine define-music-function hinein.
\version "2.19.83"

test =
#(define-music-function (p)
   (ly:pitch?)
   #{
     \new Staff \transpose c $p \relative c'' { cis e g }
   #})

xtest =
#(define-scheme-function (p q) (ly:pitch? ly:pitch?)
   (add-score
    (list #{  \markup \fill-line \override #'(font-features . ("smcp")) \override #'(box-padding . 1)
              \override #'(thickness . 2) \override #'(font-size . 4)
              { \null \rounded-box \concat { "Meine Überschrift" } \null }
      #}))
   (add-score
    (scorify-music (test q)))
   )

mybook =
#(define-void-function (p q) (ly:pitch? ly:pitch?)
   (let* ((bk (ly:make-book $defaultpaper $defaultheader '()))
          (bk-parts
           (list
            (ly:make-book-part (list (xtest p q)))
            (ly:make-book-part (list (xtest q p))))))

     (for-each
      (lambda (bookpart) (ly:book-add-bookpart! bk bookpart))
      bk-parts)

     (ly:book-process
      bk
      $defaultpaper
      $defaultlayout
      (ly:parser-output-name))))

\mybook c d


Wenn sich das anders lösen lässt, würde es mich freuen :-)
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: harm6 am Dienstag, 25. Februar 2020, 20:13
ZitatWeil ich eine Überschrift als markup habe, und das markup kriege ich in keine define-music-function hinein.
Eigentlich soll das markup ja in den bookpart hinein ;)
Möglicherweise könnte man etwas mit einem bookpart-header versuchen. Aber book und boopart sind sone Geschichte...
Ich habs jetzt nur für natives markup gemacht:


\version "2.19.83"

test =
#(define-music-function (p)
   (ly:pitch?)
   #{
     \new Staff \transpose c $p \relative c'' { cis e g }
   #})

xtest =
#(define-scheme-function (p q) (ly:pitch? ly:pitch?)
  (scorify-music (test p)))
 
#(define (make-book-parts-with-top-markup markup scores)
  (let ((bp (ly:make-book-part '())))
    (for-each
      (lambda (score) (ly:book-add-score! bp score))
      (cons (list markup) scores))
    bp))
 
myMarkup =
\markup
  \fill-line
    \override #'(font-features . ("smcp"))
    \override #'(box-padding . 1)
    \override #'(thickness . 2)
    \override #'(font-size . 4)
   { \null \rounded-box \concat { "Meine Überschrift" } \null }
   
mybook =
#(define-void-function (fall-back p) ((string? "top-markup-missing?") ly:pitch?)
  (let* ((bk (ly:make-book $defaultpaper $defaultheader '()))
         (top-markup (if (defined? 'myMarkup) myMarkup fall-back))
         (bk-parts
           (list
             (make-book-parts-with-top-markup
               top-markup
               (list (xtest p p)))
             (make-book-parts-with-top-markup top-markup
               (list (xtest p p) (xtest #{ d #} p) )))))

    (for-each
      (lambda (bookpart) (ly:book-add-bookpart! bk bookpart))
      bk-parts)
 
    (ly:book-process
      bk
      $defaultpaper
      $defaultlayout
      (ly:parser-output-name))))

\mybook c


HTH,
  Harm

Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: Manuela am Dienstag, 25. Februar 2020, 20:44
Danke Harm, das hilft mir erst mal weiter.

Jetzt muss ich das Markup zu einer Funktion umbauen, wo als Parameter ebenfalls die Tonhöhe vorkommt. Mal sehen, ob ich das gebacken kriege...
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: Manuela am Dienstag, 25. Februar 2020, 21:25
Danke Harm, du hast mir sehr geholfen.

Ein Problem ist jetzt aufgetaucht. Wenn ich die Funktion 2x ausführe, kommt nur der letzte Teil heraus. Wahrscheinlich nur eine Kleinigkeit.

Und noch eine Frage: wenn ich in den verschiedenen bookparts unterschiedliche \paper-Einstellungen haben will, z.B. top-markup-spacing.minimum-distance etc, wie kann ich das machen?

\version "2.19.83"

test =
#(define-music-function (p)
   (ly:pitch?)
   #{
     \new Staff \transpose c $p \relative c'' { cis e g }
   #})

xtest =
#(define-scheme-function (p q) (ly:pitch? ly:pitch?)
   (scorify-music (test p)))

#(define (make-book-parts-with-top-markup markup scores)
   (let ((bp (ly:make-book-part '())))
     (for-each
      (lambda (score) (ly:book-add-score! bp score))
      (cons (list markup) scores))
     bp))

#(define (pitch-alteration-semitones pitch)
   (inexact->exact (round (* (ly:pitch-alteration pitch) 2))))

#(define (conditional-string-downcase str condition)
   (if condition
       (string-downcase str)
       str))

%% Notenname als Markup mit deutschen Notennamen
#(define (note-name->my-markup pitch lowercase?)
   (let* ((name (ly:pitch-notename pitch))
          (alt-semitones (pitch-alteration-semitones pitch))
          (n-a (if (member (cons name alt-semitones) `((6 . -1) (6 . -2)))
                   (cons 7 (+ 1 alt-semitones))
                   (cons name alt-semitones))))
     (make-line-markup
      ;(make-simple-markup
      (list
       (string-append
        (conditional-string-downcase
         (list-ref '("C" "D" "E" "F" "G" "A" "H" "B") (car n-a))
         lowercase?)
        (if (or (equal? (car n-a) 2) (equal? (car n-a) 5))
            (list-ref '( "ses" "s" "" "is" "isis") (+ 2 (cdr n-a)))
            (list-ref '("eses" "es" "" "is" "isis") (+ 2 (cdr n-a)))))))))

#(define-markup-command (my-header layout props p text1 text2) (ly:pitch? string? string?)
   (interpret-markup layout props
     #{ \markup \fill-line \override #'(font-features . ("smcp"))
        \override #'(box-padding . 1)
        \override #'(thickness . 2) \override #'(font-size . 4)
        { \null \rounded-box \concat { $text1 #(note-name->my-markup p #f) $text2 } \null }
     #}))

mybook =
#(define-void-function (p) (ly:pitch?)
   (let* ((bk (ly:make-book $defaultpaper $defaultheader '()))
          (my-kadenzen #{ \markup \my-header ##{ $p #} "Kadenzen " "-Dur" #} )
          (my-dreiklang #{ \markup \my-header ##{ $p #} "Leitereigene Dreiklänge " "-Dur" #} )
          (my-vierklang #{ \markup \my-header ##{ $p #} "Leitereigene Vierklänge " "-Dur" #} )
          (bk-parts
           (list
            (make-book-parts-with-top-markup
             my-kadenzen
             (list (xtest p p)))
            (make-book-parts-with-top-markup
             my-dreiklang
             (list (xtest p p) (xtest #{ d #} p)))
            (make-book-parts-with-top-markup
             my-vierklang
             (list (xtest p p) (xtest #{ d #} p)))
            )))
     (for-each
      (lambda (bookpart) (ly:book-add-bookpart! bk bookpart))
      bk-parts)
     (ly:book-process
      bk
      $defaultpaper
      $defaultlayout
      (ly:parser-output-name))))

\mybook ##{ des #}
\mybook ##{ as #}
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: harm6 am Mittwoch, 26. Februar 2020, 00:09
ZitatEin Problem ist jetzt aufgetaucht. Wenn ich die Funktion 2x ausführe, kommt nur der letzte Teil heraus. Wahrscheinlich nur eine Kleinigkeit.

Wir machen die books ja jetzt selber, d.h. auch die Namen. Bis jetzt haben die books alle denselben Namen, somit überschreibt ein book das andere.
Du könntest z.B. so vorgehen:
      (ly:parser-output-name)
=>
      (format #f "~a-~a"
        (ly:parser-output-name)
        (markup->string (note-name->my-markup p #f)))

Zitat
Und noch eine Frage: wenn ich in den verschiedenen bookparts unterschiedliche \paper-Einstellungen haben will, z.B. top-markup-spacing.minimum-distance etc, wie kann ich das machen?
Das ist schwieriger.
Es gibt keine programmatische Funktion, die das macht. Das liegt auch an der meines Erachtens unvollkommenen Umsetzung von book und bookpart.
Man könnte auch sagen, das Ganze ist buggy ... lol

Aber man kann ja erforschen, ob man tricksen kann.
Heut abend aber nicht mehr, ist zu spät.

Gruß,
  Harm
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: Manuela am Mittwoch, 26. Februar 2020, 05:07
Danke für deine Mühe, Harm!

Das book und bookpart buggy ist, hast du schon mehrmals geschrieben.

Der Clou an der Sache für mich wäre gewesen, ein einziges Ausgabefile für mehrere Funktionsaufrufe zu erzeugen. Es ist ziemlich umständlich, die Ausgabedateien nachträglich zu einem PDF zusammen zu fügen.

Gibt es eine Möglichkeit, die einzelnen Ausgabendateien zu einer Datei zusammen zu hängen? Vll eine Pitchliste erzeugen und diese mappen? Wenn ich nur besser Scheme könnte...
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: harm6 am Mittwoch, 26. Februar 2020, 09:41
ZitatDer Clou an der Sache für mich wäre gewesen, ein einziges Ausgabefile für mehrere Funktionsaufrufe zu erzeugen.
Ich würd jetzt nicht so schnell die Flinte ins Korn werfen.  ;)


ZitatEs ist ziemlich umständlich, die Ausgabedateien nachträglich zu einem PDF zusammen zu fügen.
Hmm, mag sein, daß ein Mißverständnis auf meiner Seite besteht.
Ich hatte mich von Deinem anfänglichen Beispiel leiten lassen, in dem Du explizit ein book schaffst.

Du willst vielmehr ein einziges book?
(Falls ja, dann darf die void-function kein book erzeugen.)

Gruß,
  Harm
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: Manuela am Mittwoch, 26. Februar 2020, 09:54
Wenn die Lösung mit einer Ausgabedatei für jeden Aufruf (=pitch) nur auf einem Missverständnis beruht, bin ich froh ;)

Ich hätte gerne alle Ausgaben in einer Datei, egal wie oft die Funktion aufgerufen wird (mybook ist daher ein irreführende Name, sollte eher mybookpart heißen)
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: harm6 am Mittwoch, 26. Februar 2020, 10:20
Ok, ich komm' aber frühestens heute abend dazu, hier weiterzumachen.
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: Manuela am Mittwoch, 26. Februar 2020, 10:25
Kein Problem, danke für deine Hilfe!
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: harm6 am Donnerstag, 27. Februar 2020, 00:01
Vielleicht:


\version "2.19.83"

test =
#(define-music-function (p)
  (ly:pitch?)
  #{
    \new Staff \transpose c $p \relative c'' { cis e g }
  #})

xtest =
#(define-scheme-function (p q) (ly:pitch? ly:pitch?)
  (scorify-music (test p)))
   
foo = \paper { ragged-right = ##f }

#(define (make-book-parts-with-top-markup markup scores)
  (let* ((output-def (ly:make-output-def))
         (raw-paper
           (begin
             (ly:output-def-set-variable! output-def 'is-paper #t)
             output-def))
         (bp  #{ \bookpart { $raw-paper } #}))
         
    (for-each
     (lambda (score) (ly:book-add-score! bp score))
     (cons (list markup) scores))
     
    bp))
     
#(define (fill-book-part-paper! bookpart key-value-alist)
  (for-each
    (lambda (key-value)
      (ly:output-def-set-variable!
        (ly:book-paper bookpart) (car key-value) (cdr key-value)))
    key-value-alist))

#(define (pitch-alteration-semitones pitch)
   (inexact->exact (round (* (ly:pitch-alteration pitch) 2))))

#(define (conditional-string-downcase str condition)
  (if condition
      (string-downcase str)
      str))

%% Notenname als Markup mit deutschen Notennamen
#(define (note-name->my-markup pitch lowercase?)
  (let* ((name (ly:pitch-notename pitch))
         (alt-semitones (pitch-alteration-semitones pitch))
         (n-a (if (member (cons name alt-semitones) `((6 . -1) (6 . -2)))
                  (cons 7 (+ 1 alt-semitones))
                  (cons name alt-semitones))))
    (make-line-markup
     ;(make-simple-markup
     (list
      (string-append
       (conditional-string-downcase
        (list-ref '("C" "D" "E" "F" "G" "A" "H" "B") (car n-a))
        lowercase?)
       (if (or (equal? (car n-a) 2) (equal? (car n-a) 5))
           (list-ref '( "ses" "s" "" "is" "isis") (+ 2 (cdr n-a)))
           (list-ref '("eses" "es" "" "is" "isis") (+ 2 (cdr n-a)))))))))

#(define-markup-command (my-header layout props p text1 text2)
  (ly:pitch? string? string?)
  (interpret-markup layout props
    #{
       \markup
         \fill-line
           \override #'(font-features . ("smcp"))
           \override #'(box-padding . 1)
           \override #'(thickness . 2)
           \override #'(font-size . 4)
         {
           \null
           \rounded-box \concat { $text1 #(note-name->my-markup p #f) $text2 }
           \null
         }
    #}))
     
#(define (add-bookparts-to-toplevel-bookparts pitch)
  (let* ((bk (ly:make-book $defaultpaper $defaultheader '()))
         (my-kadenzen
           #{ \markup \my-header ##{ $pitch #} "Kadenzen " "-Dur" #})
         (my-dreiklang
           #{
              \markup \my-header ##{ $pitch #} "Leitereigene Dreiklänge " "-Dur"
           #})
         (my-vierklang
           #{
              \markup \my-header ##{ $pitch #} "Leitereigene Vierklänge " "-Dur"
           #})
         (paper-kadenzen #{ \paper { line-width = 120 ragged-right = ##f } #})
         (paper-dreiklang #{ \paper { top-markup-spacing.padding = 40 } #})
         (paper-vierklang #{ \paper { top-markup-spacing.padding = 20 } #})
         (bk-parts
          (list
           (make-book-parts-with-top-markup
            my-kadenzen
            (list (xtest pitch pitch)))
           (make-book-parts-with-top-markup
            my-dreiklang
            (list (xtest pitch pitch) (xtest #{ d #} pitch)))
           (make-book-parts-with-top-markup
            my-vierklang
            (list (xtest pitch pitch) (xtest #{ d #} pitch))))))
           
    (for-each
      (lambda (book-part key-values)
        (fill-book-part-paper! book-part key-values))
      bk-parts
      (map
        (lambda (paper)
          (ly:module->alist (ly:output-def-scope paper)))
        (list paper-kadenzen paper-dreiklang paper-vierklang)))
               
               
    (for-each
      (lambda (book-part)
        (ly:parser-define! 'toplevel-bookparts
          (cons book-part (ly:parser-lookup 'toplevel-bookparts))))
      bk-parts)))
 
myBookparts =
#(define-void-function (mus) (ly:music?)
  (let ((pitches (music-pitches mus)))
    (for-each
      (lambda (pitch) (add-bookparts-to-toplevel-bookparts pitch))
      pitches)))

\myBookparts < des aes >


HTH,
  Harm
Titel: Antw:Mehrere bookparts in einer Funktion ausgeben - geht das?
Beitrag von: Manuela am Donnerstag, 27. Februar 2020, 09:15
Danke Harm für die viele Mühe, die du dir für gemacht hast.

Das klappt alles ganz wunderbar  :) :) :)