Mehrere bookparts in einer Funktion ausgeben - geht das? ---> gelöst

Begonnen von Manuela, Montag, 24. Februar 2020, 17:43

« vorheriges - nächstes »

Manuela

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?
Danke für eure Hilfe
viele Grüße
-- Manuela

harm6


\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

Manuela

Danke Harm. Das ist sehr hilfreich für mich  :)

Der Beispielcode ist natürlich grober Unfug, mein tatsächlicher Code ist ein wenig sinnvoller ;-)
Danke für eure Hilfe
viele Grüße
-- Manuela

Manuela

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.  :( :-[
Danke für eure Hilfe
viele Grüße
-- Manuela

Manuela

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
Danke für eure Hilfe
viele Grüße
-- Manuela

harm6

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

Manuela

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 :-)
Danke für eure Hilfe
viele Grüße
-- Manuela

harm6

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


Manuela

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...
Danke für eure Hilfe
viele Grüße
-- Manuela

Manuela

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 #}
Danke für eure Hilfe
viele Grüße
-- Manuela

harm6

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

Manuela

#11
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...
Danke für eure Hilfe
viele Grüße
-- Manuela

harm6

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

Manuela

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)
Danke für eure Hilfe
viele Grüße
-- Manuela

harm6

Ok, ich komm' aber frühestens heute abend dazu, hier weiterzumachen.