Deutsches Lilypond Forum (Archiv)
Allgemein => Hilfe beim Einstieg in Lilypond => Thema gestartet von: ingmar am Donnerstag, 24. März 2016, 21:40
-
Ich habe vier Partituren, die eigentlich identisch sind bis auf die Variable, aus der die Musik kommt:
\version "2.19.37"
MUSIK = \relative c'' { c4 d e f c d e f g f e d g f e d }
\score {
\MUSIK
}
Weil ich die Partitur aus verschiedenen Schnipseln zusammensetzen möchte, muss ich den Namen der Variablen erst "berechnen", sprich, zusammenbasteln. Ich brauche also sowas wie:
Variable1 = "\M"
Variable2 = "US"
Variable3 = "IK"
\score {
eval ( Variable1 & Variable2 & Variable3)
}
Wie krieg ich das hin?
--ingmar
[EDIT: Typo]
-
Was du suchst, sind string-append zum Zusammensetzen von Strings und ly:parser-include-string als eine Art „eval“:
\version "2.19.38"
MUSIK = \relative {
c' d e f g2 g
}
mu = "MU"
sik = "SIK"
#(ly:parser-include-string (string-append "\\" mu sik))
-
Danke, klappt gut. : - )
--ingmar
-
Aber kann man Lilypond auch dazu bringen, eine Variable nicht bei der Definition auszuwerten, sondern dann, wenn sie verwendet wird?
\version "2.19.37"
MUSIK-A = \relative {
c'4 d e f g2 g
}
MUSIK-B = \relative {
c''4 b a g f2 f
}
pointer = "MUSIK-A"
soso = \score {
\new Staff { #(ly:parser-include-string (string-append "\\" pointer)) }
}
\soso
pointer = "MUSIK-B"
\soso
Ich definiere oben eine Variable soso als \score, der sich seine Inhalte aus dem Wert der Variablen pointer nimmt. Nun definiere ich pointer um und stelle mir natürlich vor, das nun auch soso bei erneuter Verwendung einen anderen Wert hat.
Offenbar geht sowas nicht?
Danke,
--ingmar
-
How about this? Wie wärs damit?\version "2.19.37"
MUSIK-A = \relative {
c'4 d e f g2 g
}
MUSIK-B = \relative {
c''4 b a g f2 f
}
pointer = "MUSIK-A"
soso =
#(define-music-function () ()
#{
\new Staff { #(ly:parser-include-string (string-append "\\" pointer)) }
#})
\soso
pointer = "MUSIK-B"
\soso
Edit: Falls du aus irgendeinem Grund \score tatsächlich brauchst, geht das auch, dann muss es allerdings define-scheme-function statt define-music-function heißen:
soso =
#(define-scheme-function () ()
#{
\score {
\new Staff { #(ly:parser-include-string (string-append "\\" pointer)) }
}
#})
Und nein, das war keine Absicht oben, ich war wohl grad durch die Mailingliste so auf englisch gepolt :D
-
Ah! Logisch. Dazu braucht man natürlich eine Funktion.
Danke, Gruß,
--ingmar
-
fugenkomponist: Falls du aus irgendeinem Grund \score tatsächlich brauchst, ...
Doch, \score hätte sich schon gern dabei - auch mehr:
\version "2.19.37"
MUSIC = \relative { g a b c d1 }
TEXT = "Bitteschön!"
pointermusic = "MUSIC"
pointertext = "TEXT"
soso = #(define-scheme-function () ()
#{
\score {
\new Staff { #(ly:parser-include-string (string-append "\\" pointermusic )) }
}
\header {
piece = \markup #(ly:parser-include-string (string-append "\\" pointertext )) }
#})
\soso
\score klappt prima, \header leider nicht. Ich verstehe leider nicht warum. Wo liegt mein Denkfehler?
Danke, Gruß,
--ingmar
-
Eine Funktion kann nur einen Wert zurückgeben, nicht zwei (\score und \header). Du kannst aber den \header-Block in den \score-Block packen, dann geht das.
soso = #(define-scheme-function () ()
#{
\score {
\header {
piece = \TEXT
}
\new Staff { #(ly:parser-include-string (string-append "\\" pointermusic )) }
}
#})
Es ergibt sich allerdings ein anderes Problem: ly:parser-include-string funktioniert anscheinend so nicht in markups, hier
piece = \markup #(ly:parser-include-string (string-append "\\" pointertext))
beschwert LilyPond sind über „not a markup“.
Dapiece = \markup \TEXT
genauso funktioniert wie ohne \markup, hab ich also auch das mal ohne probiert:
piece = #(ly:parser-include-string (string-append "\\" pointertext))
Das liefert aber weder nen Fehler, noch wird irgendetwas als piece-Header ausgegeben, keine Ahnung, warum …
-
So, hab ne Lösung:
Statt nen String zusammen zu basteln und den an den LilyPond-Parser zu füttern, damit LilyPond am \ eine Variable erkennt und den Inhalt der Variable dieses Namens holt, gehts mit ein bisschen weniger Umweg direkt in Scheme: Der String wird zu nem Symbol gemacht und Scheme holt den Inhalt der Variable dieses Namens.
\version "2.19.37"
MUSIC = \relative { g a b c d1 }
TEXT = "Bitteschön!"
pointermusic = "MUSIC"
pointertext = "TEXT"
soso = #(define-scheme-function () ()
#{
\score {
\header {
piece = #(module-ref (current-module) (string->symbol pointertext))
}
\new Staff { #(ly:parser-include-string (string-append "\\" pointermusic )) }
}
#})
\soso
Das funktioniert auch an anderen Stellen (sodaß hier ly:parser-include-string und string-append gar nicht mehr nötig sind), außerdem kann man sich string->symbol sparen, wenn man gleich Symbole definiert:
\version "2.19.37"
MUSIC = \relative { g a b c d1 }
TEXT = "Bitteschön!"
pointermusic = #'MUSIC
pointertext = #'TEXT
soso = #(define-scheme-function () ()
#{
\score {
\header {
piece = #(module-ref (current-module) pointertext)
}
\new Staff {
#(module-ref (current-module) pointermusic)
}
}
#})
\soso
Edit: Das Stichwort, wonach ich gesucht hab, lautet „Reflection“ (gibts auch in anderen Programmiersprachen wie z. B. Java). Gefunden hab ich dann diesen Abschnitt (https://www.gnu.org/software/guile/docs/docs-1.8/guile-ref/Module-System-Reflection.html#Module-System-Reflection) der Guile-Dokumentation, wo module-ref und current-module (sowie weitere Funktionen) dokumentiert sind.
2. Edit: Ich habs tatsächlich nicht da gefunden, sondern im entsprechenden Abschnitt (https://www.gnu.org/software/guile/manual/html_node/Module-System-Reflection.html) der Guile-2.0-Dokumentation. Warum das in 1.8 auch funktioniert, aber anscheinend nicht dokumentiert ist (ich hatte den Link oben angegeben, ohne nochmal den genauen Inhalt der Seite zu prüfen), ist mir nicht klar …
-
Warum das in 1.8 auch funktioniert, aber anscheinend nicht dokumentiert ist (ich hatte den Link oben angegeben, ohne nochmal den genauen Inhalt der Seite zu prüfen), ist mir nicht klar …
Es gibt jede Menge undokumentierte procedures, etc in guile. Wer wirklich tief einsteigen möchte wird wohl nicht umhin kommen das guile-git-repository runter zu laden.
Wenn man aber weiß (oder vermutet), daß etwas existieren könnte kann man so vorgehen:
guile> (version)
"1.8.8"
guile> module-ref
#<procedure module-ref (module name . rest)>
guile> (procedure-source module-ref)
(lambda (module name . rest) (let* ((variable (module-variable module name))) (if (and variable (variable-bound? variable)) (variable-ref variable) (if (null? rest) (error "No variable named" name (quote in) module) (car rest)))))
guile> (help module-ref)
No documentation found for:
(guile): module-ref
guile>
Den Code kann man jetzt natürlich noch besser formatieren ...
Darüberhinaus wird auch die guile-Doku laufend verbessert, passiert mit LilyPond ja glaichfalls. Allerdings wird die guilev1.8.8-Doku wohl nicht mehr verändert, umso ärgerlicher, daß wir das upgrade auf guilev2 nicht hinbekommen. Liegt aber meiner Kenntnis nach eben nicht nur an uns, sondern wir werden auch von den guile-Leuten links liegen gelassen.
Zumindest drängt sich dieser Eindruck auf...
Gruß,
Harm