Verschiedene Editionen mit denselben Dateien

Begonnen von unique75m, Montag, 30. April 2018, 22:05

« vorheriges - nächstes »

Hilflos-im-Code

Fokus: Nicht unbedingt. Book und Orchestermaterial widersprechen sich.

unique75m

So nun habe ich mal Harms Beispiele getestet. Folgendes habe ich dabei festgestellt:


\version "2.18.2"

#(define-macro
(if-equal a b x y)
`(if (equal? ,a ,b) ,x ,y))

#(define var1 "visible")
#(define var2 "visible")

% Ich habe hier mal statt dem $ ein # probiert, damit funktioniert es nicht. Was ist der Unterschied zwischen $ und # ??
#(if-equal var1 var2
#{ a' b' c'' #}
#{ d'' e'' f'' #})


Das `und die Kommas innerhalb des Makros scheint wohl irgendein definierter Standard zu sein, mit Komma wählt man dann wohl einen Parameter.

Dann habe ich weiter probiert und eine zweites Makro if-visible abgeleitet und dafür die if-equal Funktion verwendet. Auch das scheint zu klappen. Mit normalen Schema-Funktionen ging das nämlich nicht wegen dem if-Befehl, weil es da keine lazy-evalution gibt. Bei den Makros scheint das doch eher wie Textersetzung zu funktionieren. D.h. damit lassen sich dann auch mal Makros in Makros schachteln und somit komplexere bedingte Ausdrücke formulieren, ohne das man jedesmal wieder mit einem if anfängt.


\version "2.18.2"

#(define-macro
(if-equal a b x y)
`(if (equal? ,a ,b) ,x ,y))

#(define-macro
(if-visible a x y)
`(if-equal ,a "visible" ,x ,y))

#(define var1 "visible")
#(define var2 "invisible")

$(if-visible var1
#{ a' b' c'' #}
#{ d'' e'' f'' #})

$(if-visible var2
#{ a' b' c'' #}
#{ d'' e'' f'' #})


Nun habe ich noch ein weiteres Makro gebaut, was auf dem if-visible aufbaut und keinen else-Zweig mehr benötigt. Der wäre in meinen Fällen eh meist leer. Dies hat bei mir auch geklappt.


\version "2.18.2"

#(define-macro
(if-equal a b x y)
`(if (equal? ,a ,b) ,x ,y))

#(define-macro
(if-visible a x y)
`(if-equal ,a "visible" ,x ,y))

#(define-macro
(if-visible-noelse a x)
`(if-visible ,a ,x #{#}))

#(define var1 "visible")
#(define var2 "invisible")

$(if-visible-noelse var1
#{ a' b' c'' #})

$(if-visible-noelse var2
#{ a' b' c'' #})


Als nächstes bin ich dann mal ganz mutig geworden und wollte den Mix von Makros und Funktionen erreichen, damit ich mittels der Funktion dann normalen Lilypond-Syntax schreiben kann. Dies klappt aber leider nicht.


\version "2.18.2"

#(define-macro
(if-equal a b x y)
`(if (equal? ,a ,b) ,x ,y))

#(define-macro
(if-visible a x y)
`(if-equal ,a "visible" ,x ,y))

#(define-macro
(if-visible-noelse a x)
`(if-visible ,a ,x #{#}))

#(define
(if-visible-noelse-func a x)
(if-visible-noelse a x))

var1 = "visible"
var2 = "invisible"

\if-visible-noelse-func \var1
{ a' b' c'' }

\if-visible-noelse-func \var2
{ a' b' c'' }


Als nächstes habe ich dann mal probiert, ob die Makros auch außerhalb von Score funktionieren. Ich habe auch gleich mal bookpart drum herum gebaut. Die Makros scheinen zu funktionieren. Damit kann ich dann mit den Makros auch einzelne Scores abschalten.


\version "2.18.2"

#(define-macro
(if-equal a b x y)
`(if (equal? ,a ,b) ,x ,y))

#(define-macro
(if-visible a x y)
`(if-equal ,a "visible" ,x ,y))

#(define-macro
(if-visible-noelse a x)
`(if-visible ,a ,x #{#}))

#(define var1 "visible")
#(define var2 "visible")

$(if-visible-noelse var1
#{
\bookpart
{
\score
{
\new Staff
{
\new Voice
{
a' b' c''
}
}
}
}
#})

$(if-visible-noelse var2
#{
\bookpart
{
\score
{
\new Staff
{
\new Voice
{
d'' e'' f''
}
}
}
}
#})


Der klitzekleine Wermutstropfen ist natürlich, dass man es nicht als normale Lilypond-Syntax schreiben kann und ein paar Klammern mehr hat. Aber ich denke damit kann ich leben  :)

Vielen Dank übrigens für die anderen Tipps bezüglich bookpart, so wird jedes Lied gleich auf einer neuen Seite angefangen. Ich denke ich werde mit den nun gewonnenen Ideen mal eins der größeren Heftchen/Bücher umsetzen. Mal sehen was da dann alles noch so für Probleme entstehen bei den Details wie Noten, Verzierungen, usw. Aber prinzipiell hat man jetzt erstmal eine vernünftige Basis, um redundanten Code zu vermeiden.

unique75m

Das hier klappt leider auch nicht mit den Makros. Irgendwie mag er nicht den \paper Block in einem Makro.


$(if-visible "visible" #{
\paper
{
(set-paper-size "a3landscape")
print-all-headers = ##t
ragged-right = ##f
} #})


Oder sowas wie den komplette \layout Block kann man auch nicht einkapseln:


$(if-visible "visible" #{
          \layout
{
\context
{
\Score
\remove "Bar_number_engraver"
}

\context
{
\Staff
\consists "Bar_number_engraver"
}

\override Score.BarNumber.break-visibility = #end-of-line-invisible
\set Score.barNumberVisibility = #(every-nth-bar-number-visible 2)
}
#})
   

Außerdem verstehe ich es nicht, wieso man mehrere \bookparts nicht in einem \book einkapseln kann. Sobald man das tut funktionieren die Makros ebenfalls wieder nicht, wenn man dann die \bookparts per if-visible einkapselt. Ohne \book gehts. Dann stehen aber \header und \paper völlig verloren da.

harm6

Hallo unique,

nur ganz kurz.
In den beiden Beispielen mit \paper und \layout stimmt die Anzahl der Argumente nicht.
Dein if-visible verlangt drei Du gibst aber nur 2.
Außerdem fehlt im \paper Beispiel ein #-Zeichen vor (set-paper-size "a3landscape").
Hast Du die error-message im terminal übersehen?

Zitat von: terminalerror: GUILE signaled an error for the expression beginning here
$
(if-visible "visible" #{
Wrong number of arguments to #<procedure #f (a x y)>


Schau mal in die guile-1.8-Doku, ob defmacro* weiterhilft, das akzeptiert auch optionale Argumente.

Ich vermute mal ähnliches passiert mit den bookparts.

Gruß,
  Harm

harm6

Nochmals hallo,

hier eine mögliche Implementierung als LilyPond-Syntax. (Ist aber nur minimal getestet.)


\version "2.19.81"

#(define *unspecified* (if #f #f))

#(define-macro
(if-equal a b x y)
`(if (equal? ,a ,b) ,x ,y))

buzz =
#(define-scheme-function (strg1)(string?)
  (define-scheme-function (strg2 expr1 expr2) (string? scheme? scheme?)
    (if-equal strg1 strg2 expr1 expr2)))
 
barr =
  \buzz
    "visible"
    %"not visible"

\barr "visible"
  \paper {
    #(set-paper-size "a3landscape")
    print-all-headers = ##t
    ragged-right = ##f
  }
  #*unspecified*


\barr "visible"
  \layout {
    \context {
      \Score
      \remove "Bar_number_engraver"
      \override BarNumber.break-visibility = #end-of-line-invisible
      barNumberVisibility = #(every-nth-bar-number-visible 2)
    }
 
    \context {
      \Staff
      \consists "Bar_number_engraver"
    }
  }
  #*unspecified*
 
 
\repeat unfold 120 c'4


Allerdings ist 2.19.x zwingend erforderlich.
Ich würd' auch dringend zuraten 2.19. zu installieren, zumindest als Zweit-Version.

Im Code oben zeigt sich aber auch eine Schwäche.
Während es bei der reinen scheme-Version klar ist wo die Argument aufhören (schon der Klammern wegen), so muß in der LilyPond-Syntax der Fall für #f angegeben werden, obwohl man sie optional machen könnte. Anderenfalls wird der nächste Ausdruck, welcher auch immer das sein mag dafür gehalten. Alternativ könnte man wahrscheinlich die Prädikate der inneren scheme-funktion weniger allgemein fassen, beraubt sich damit aber natürlich der breiteren Anwendungsmöglichleiten.

Gruß,
  Harm

Hilflos-im-Code

Zur Verwendung von \book:

Unter http://lilypond.org/doc/v2.18/Documentation/notation/multiple-scores-in-a-book steht:

ZitatEine wichtige Ausnahme stellen Dokumente dar, die mit lilypond-book erstellt werden, für die Sie explizit \book-Umgebungen notieren müssen, weil sonst nur die erste \score- bzw. \markup-Umgebung angezeigt wird.

lilypond-book ist zur Vorberteitung für Latex, aber wir wollen ja nichts für Latex vorbereiten.

Dann lese ich http://lilypond.org/doc/v2.18/Documentation/notation/multiple-output-files-from-one-input-file und frage mich, warum packt man vier verschiedene Stücke in eine Datei, um dann mit einem Befehl zu erreichen, dass jedes in einem eigenen PDF landet.


ingmar

ZitatHilflos: ...und frage mich, warum packt man vier verschiedene Stücke in eine Datei, um dann mit einem Befehl zu erreichen, dass jedes in einem eigenen PDF landet.
Na, wenn du zum Beispiel 99 Orchesterstimmen anfertigen willst, die alle einfach nur ein paar Variable in einen Score packen. Dann hätte ich persönlich statt 99 superkleinen *.ly- Files lieber nur ein einziges, und würde die Ergebnisse auch lieber in einen getrennten Folder schreiben lassen.

Hier geht es möglicherweise um Einzelsätze, und der Anforderer möchte nicht einen ungefähr gleichen Code in vier verschiedenen Files stehen haben.

--ingmar

Hilflos-im-Code

Zitat von: ingmar am Montag, 21. Mai 2018, 07:43
Hier geht es möglicherweise um Einzelsätze, und der Anforderer möchte nicht einen ungefähr gleichen Code in vier verschiedenen Files stehen haben.

--ingmar

Also Du suchst eine Lösung für etwas, wo die dir die Endanforderung nicht klar ist.

Die Endanforderung ist, wie weiter oben steht.

Wenn du damit meine generelle Vorgehensweise meinst, dass ich 4 Scores in ein Book packe... ich dachte das wäre eine gute Idee, weil ich doch eben in der Realität ein kleines Buch mit 4 Liedern haben. Naja ich will es ja nicht unbedingt als Buch bezeichnen, eher Heftchen. Aber es  sind inhaltlich zusammengehörige Stücke. Da habe ich also einen Titel für das Heft/Buch und eben pro Lied verschiedene eigene Titel. Nach meinen bisherigen Erkenntnissen aus der Lilypond-Doku erschien mir das als sinnvoller Weg. Wenn es da etwas besseres gibt, bin ich für Vorschläge offen.

Die Frage nach EInzelstimmenauszug wurde bisher nicht beantwortet. Wobei ich dann die austomatisierten Namensgebung der End-PDFs nicht sehr hilfreich für die später Verwendung finde. Und schon  gar nicht bei deinen fiktiven 99 Einzelstimmen eines Orchesters. Denn man druckt dann z.B. viermal die erste Geige aus, aber nur einmal die Flöte. Bei Dateinamen wie
 

  • 'eightminiatures.pdf',
  • 'eightminiatures-1.pdf'
  • 'eightminiatures-2.pdf'.


stelle ich mir das nicht sehr praktisch vor.

Wobei das Orchester mit 99 Einzelstimmen, nicht  Einzelmusiker möchte ich sehen und ganz besonders im Musikschulbereich.

ingmar


unique75m

Lieber Harm,

ja da hast du natürlich Recht mit der Anzahl der Argumente in meinen Beispielen. Ich bin mir da gerade selbst nicht mehr sicher, ob ich nicht schon die Makros umgebaut hatte namentlich, was natürlich angesichts der vorausgehenden Beispiele für alle Anwesenden hier verwirrend ist. Ich entschuldige mich dafür :-)

Ich habe also gleich nochmal die alten Makros kopiert und eine Testdatei zusammengestellt mit folgendem Inhalt. Die relevanten Stellen sind auskommentiert, sodaß es in dieser Form fehlerfrei kompiliert. Sobald man die Kommentarzeichen entfernt, gibt es den Fehler, dass er einen unexpected \header hat.


#(define-macro
(if-equal a b x y)
`(if (equal? ,a ,b) ,x ,y))

#(define-macro
(if-visible a x y)
`(if-equal ,a "visible" ,x ,y))

#(define-macro
(if-visible-noelse a x)
`(if-visible ,a ,x #{#}))

\version "2.18.2"

\paper
{
#(set-paper-size "a3landscape")
print-all-headers = ##t
ragged-right = ##f
}

myvar = "visible"

\bookpart
{
\score
{
% $(if-visible-noelse myvar
% #{
\header
{
dedication = ""
    title = "Test"
    subtitle = ""
subsubtitle = ""
instrument = ""
poet = ""
composer = ""
meter = ""
arranger = ""
tagline = ""
copyright = ""
piece = ""
opus = ""
}
% #})

\new Staff
{
\new Voice
{
a' b' c''
}
}
}
}


Deine Lösung für 2.19.x habe ich syntaktisch noch nicht ganz erfasst, aber auf den 1. Blick sieht es so aus, als würde man eine Funktion bauen, die eine Funktion zurückgibt, wo der Parameter der 1. Funktion in die 2. Funktion hinein kompiliert wird. Erinnert mich stark an BlockClosures, die BlockClosures zurückgeben deren innere Parameter von außen hineingeschleust werden, sowas ähnliches habe ich schon in Smalltalk gemacht. Deine Folgebeispiele mit \buzz und \barr verstehe ich so, dass ich jetzt in meinen Edition-Dateien statt:

    scoreA = "visible"

nun für die Deklaration derselben Variablen schreibe:

    scoreA = \buzz "visible"

Und dann habe ich ein neues Lilypond-Kommando scoreA, dem ich den Vergleichstring und 2 musikalische Blöcke als Parameter schicke

    \scoreA "visible" xxx yyyy

Wenn ich diese Vorgehensweise mit der Funktion-in-Funktion nun kombiniere mit dem if-equal-else Makro, anstatt if-equal, dann bräuchte ich ja keinen Parameter yyyy mehr und somit auch nicht das unspecified. Muss ich mal demnächst testen :-)

Was konkret ist daran jetzt nur 2.19.x kompatibel? Diese Sache mit dem Zurückgeben der Funktion aus einer Funktion, also die Definition von buzz?

Wenn das alles funktioniert wie gedacht, dass ist es natürlich eine deutlich schönere und kürzere Schreibweise, anstatt diese ständigen Wechsel zwischen Lillypond und Scheme und den zig Klammern. Man wird hier ganz beklammert :-)

unique75m

Lieber Ingmar,

wenn Du 99 Orchesterstimmen hast, dann hat man doch meiner Meinung nach noch mehr diese Probleme, die ich geschildert habe. Man schreibt doch dann einmal eine Struktur für die gesamte Partitur mit 99 Stimmen. Natürlich kann man dann Dinge wie Texte, Instrumentnamen oder Noten per Variablen herausziehen, damit diese nur einmalig definiert werden.

Wenn aber nun ein Musiker schreit, der eben nicht die Gesamtpartitur haben will, sondern nur seine Einzelstimme, dann fange ich doch jetzt eigentlich an einen Teil der Gesamtstruktur herauszukopieren und nochmals irgendwo in einem zweiten \book oder \bookpart abzulegen. Da ich in dem Fall lieber pessimistisch bin, gehe ich davon aus, dass alle 99 Musiker schreien und jeder seine eigene Stimme einzeln will. Das heißt dann habe ich also 99 mal redundanten Strukturcode. Wenn man dann ein halbes Jahr später irgendeinen Fehler entdeckt im Strukturcode und mit einer Änderung beheben will, dann muss ich diese Änderung ja auf einmal an 99 + 1 (Gesamtpartitur-Struktur) Strukturen nachziehen. Deswegen macht es Sinn solche Redundanzen erst garnicht zuzulassen.

Ob ich die 99 + 1 nun in einzelne Dateien ablege oder zusammen in eine große spielt dabei eigentlich keine Rolle, es bleibt redundant. Für mich persönlich sind dann solche großen Dateien, auch angesichts der vielen Klammern bei Lilypond und Scheme, dann nicht mehr wartbar. Ich stelle mir gerade vor wie ich in einer Riesendatei mit 99 Stimmen Strukturcode dann die Stimme 67 finde und hoffe dass ich da ja die richtige Klammerung erwischt habe.

Wenn ich jetzt große Dateien nicht so schrecklich unübersichtlich finden würde, könnte ich natürlich auch alles in eine Datei legen und dort ebenfalls per ConditionalCompiling bestimmte Pfade ausschließen.

harm6

Zitat von: unique
Sobald man die Kommentarzeichen entfernt, gibt es den Fehler, dass er einen unexpected \header hat.

<code-Beispiel>

Das kann ich für 2.18.2 bestätigen in 2.19.81 gehts problemlos.

Zitat von: unique
Deine Lösung für 2.19.x habe ich syntaktisch noch nicht ganz erfasst,
[...]
Muss ich mal demnächst testen :-)
Ich bin mir nicht ganz sicher, ob Deine Beschreibungen korrekt sind, da bräuchte ich den Code, wie genau Du es umgesetzt/angewendet hast.

Allerdings:
Zitat von: uniqueWas konkret ist daran jetzt nur 2.19.x kompatibel? Diese Sache mit dem Zurückgeben der Funktion aus einer Funktion, also die Definition von buzz?
Das Zurückgeben einer Funktion aus einer Funktion hat früher schon geklappt.
Ich kann dir nur berichten, daß mein obiges Beispiel mit 2.18.2 einen error erzeugt:
Zitat von: terminalerror: bad expression type

\barr "visible"
Und der Code ansonsten keine Wirkung zeigt.
Leider kann ich Dir nicht genau sagen woran es in 2.18.2 hapert.
Seitdem ist seeeehr viel passiert. Dunkel erinnere ich mich an Änderungen im parser/lexer was erlaubt ist (oder auch nicht).
Insbesondere in #{ ... #}

Wie schon gesagt, ich würde 2.19. installieren. Es ist soooo viel besser. Auch sind parallel-Installationen kein Problem. Anleitungen finden sich auch hier im Forum oder in der Doku. Oder frag einfach danach.
Ich schreib jetzt nicht wie ich das mache, weil meine Methode etwas umständlich ist. Ich komm aber gut damit klar und bin zu faul das setup zu ändern ;)
aber ich hab diverse Versionen auf dem Rechner:
2.21.0 mit guile-2.2.3
2.21.0 mit guile-1.8
2.19.81
2.18.2
2.16.2
2.14.2
2.12.3

Die ersten beiden selbst kompiliert aus dem git-repository. Die älteren sind vor allem für bug-recherchen nützlich. Diese Versionen sind nicht mehr aus dem repository kompilierbar. Dazu bräuchte man ältere Versionen von (vor allem) gcc und anderen Programmen.
Falls es doch nötig wird, so fahre ich eine der alten LilyDev in einer VB hoch ...

Aber ich schweife ab :)

Gruß,
  Harm


Hilflos-im-Code

#57
Zitat von: unique75m am Montag, 21. Mai 2018, 19:06

Wenn aber nun ein Musiker schreit, der eben nicht die Gesamtpartitur haben will, sondern nur seine Einzelstimme, dann fange ich doch jetzt eigentlich an einen Teil der Gesamtstruktur herauszukopieren und nochmals irgendwo in einem zweiten \book oder \bookpart abzulegen. Da ich in dem Fall lieber pessimistisch bin, gehe ich davon aus, dass alle 99 Musiker schreien und ...

Die Realität sieht, wenn die Partitur größer als zwei oder drei Seiten hat, anders aus. Die Musiker bekommen Einzelstimmen, wenn Sie wollen bekommen sie eine Partitur in handlichem Format. Also das Anfertigen von Einzelstimmen ist der Normalmalfall.

In den normalen Notensatzprogrammen sieht das so aus. Du schreibst die Partitur und ziehst via Automatismus die Einzelstimmen heraus.

In Lilypond schreibst Du die Einzelstimmen und klebst sie dann zusammen. Siehe als Beispiel http://www.mutopiaproject.org/cgibin/make-table.cgi?searchingfor=Divertimento+in+Bb+Major+mozart . Das dürfte deinem Endprodukt vermutlich in gewisserweise entsprechen. Der Weg dahin weniger.

Bloß als Musikschullehrer würde ich so etwas nicht machen wollen. Wenn ich für eine Kammermusikgruppe etwas einrichte, will/muss ich die Partitur vor mir haben.