Deutsches Lilypond Forum (Archiv)
Allgemein => Fragen zu Funktionen => Thema gestartet von: Manuela am Freitag, 29. Juli 2016, 12:02
-
Immer wenn ich denke, ich habe es kapiert, falle ich auf die Nase :( >:(
Ich möchte, dass die Oktavierungsklammern am höchsten stehen, und habe outside-staff-priority gesetzt. Doch es funktioniert nicht wie gewünscht, was mache ich falsch?
\version "2.19.37"
\language "deutsch"
mymus= { \repeat unfold 3 c4 }
RH = \relative c'' {
\override Staff.OttavaBracket.outside-staff-priority = #2000
c \mymus
% Die Noten folgen hier.
\ottava #1 c'' \mymus
}
LH = \relative c {
\clef bass
% Die Noten folgen hier.
c \mymus
}
Akk=\chordmode {
\set alignAboveContext = #"up"
c1 c
}
\score
{
\new PianoStaff
<<
\new Staff="up"
<<
\context ChordNames \Akk
\context Voice \RH
>>
\new Staff="down"
\context Voice \LH
>>
\layout {
}
}
-
Das liegt daran, dass ChordNames und Staff zwei gleichberechtigte Kontexte sind (wie zwei Staffs) und nicht ChordNames Teil des Staffs (wie eine Voice im Staff). Du sagst ja auch „plaziere den ChordNames-Kontext über den oberen Staff-Kontext“ ;) Ehrlich gesagt wundert es mich gerade, dass dir das nicht um die Ohren fliegt, wenn du nen ChordNames-Kontext in nen Staff packst.
Man kann nun probieren, so etwas per \accepts zu erzwingen (also in etwa \new Staff = "up" \with { \accepts \ChordNames } << \new ChordNames …), aber da LilyPond das nicht „gewohnt“ ist, muss man sich dann um die vertikale Positionierung der ChordName-Grobs selbst kümmern. Die OttavaBracket passt sich dann schon an. Hier mal mein Ergebnis (habe für mich für die Übersicht die überflüssigen Voice-Kontexte rausgeschmissen, kannst du für dich auch wieder reinnehmen, auch wenns für LilyPond keinen Unterschied macht):\version "2.19.37"
\language "deutsch"
mymus= { \repeat unfold 3 c4 }
RH = \relative c'' {
c \mymus
\ottava #1 c'' \mymus
}
LH = \relative c {
\clef bass
c \mymus
}
Akk = \chordmode {
c1 c
}
\score
{
\new PianoStaff
<<
\new Staff = "up" \with {
\accepts ChordNames
}
<<
\new ChordNames \with {
\override ChordName.Y-offset = 5 % dieser Wert entsteht durch Ausprobieren
} \Akk
\RH
>>
\new Staff = "down" \LH
>>
\layout {
}
}
-
Danke fugenkomponist für deine unermüdliche Hilfe :) Du hast den viel besseren Durchblick :D
Das liegt daran, dass ChordNames und Staff zwei gleichberechtigte Kontexte sind (wie zwei Staffs) und nicht ChordNames Teil des Staffs (wie eine Voice im Staff). Du sagst ja auch „plaziere den ChordNames-Kontext über den oberen Staff-Kontext“ ;) Ehrlich gesagt wundert es mich gerade, dass dir das nicht um die Ohren fliegt, wenn du nen ChordNames-Kontext in nen Staff packst.
Ich habe eine XML-Datei importiert, daher die Context- und Voice-Anordnungen. Einzig \set alignAboveContext = #"up" habe ich dazugepackt.
Das wäre dann die "saubere" Variante?
\version "2.19.37"
\language "deutsch"
mymus= { \repeat unfold 3 c4 }
RH = \relative c'' {
c \mymus
\ottava #1 c'' \mymus
}
LH = \relative c {
\clef bass
c \mymus
}
Akk=\chordmode {
c1 c
}
\score
{
\new PianoStaff
<<
\new ChordNames ="chords" \Akk
\new Staff="up" \RH
\new Staff ="down" \LH
>>
\layout {
}
}
Wie würde es denn gehen, sodass die Ottava-Bracket über allem schwebt?
\override Staff.OttavaBracket.outside-staff-priority = #2000
\override OttavaBracket.padding = #25
bewirkt nämlich genau gar nix
Update: ich sehe gerade, die ChordNames standen urspünglich außerhalb des Staffs, ich habe das im Zuge der Erstellung des Minimalbeispiels unbeabsichtigt verändert (immer nach dem Motto: denn sie wissen nicht was sie tun :-[)
-
Das wäre dann die "saubere" Variante?
Ja.
Wie würde es denn gehen, sodass die Ottava-Bracket über allem schwebt?
Das ist das Problem: Es sind zwei unabhängige Kontexte (ChordNames und Staff) übereinander. Das ist also ne ähnliche Situation wie wenn du im unteren System ne OttavaBracket hättest und die übers obere System schieben wolltest. Das geht nur mit nem extra-offset, weil mit nem normalen padding oder Y-offset die ChordNames entsprechend Platz machen würden, um weiter darüber zu bleiben.
\once \override Staff.OttavaBracket.outside-staff-priority = #'()
\once \override Staff.OttavaBracket.Y-offset = 0
\once \override Staff.OttavaBracket.extra-offset = #'(0 . 8.5)Das ist ein Trick: die erste Zeile sorgt dafür, dass die Klammer nicht mehr unbedingt außerhalb des Systems liegen will. Nur dadurch kann man sie nämlich mit der zweiten Zeile mitten ins System reinsetzen*. Mit der dritten Zeile wird sie dann wieder rausgeschoben, ohne aber das Spacing zu beeinflussen (du kannst das nachvollziehen, indem du erst die zweite, dann die erste und dann die dritte Zeile in deinen Code einfügst und dir das Ergebnis anschaust). Nachteil dieser Lösung (und der Grund, warum man extra-offset nur mit Vorsicht verwenden sollte): Es kann sein, dass der Abstand zu Titeln/vorherigen Systemen zu klein wird, weil die Skyline (s. Anhang) die verschobene Klammer nicht berücksichtigt (LilyPond geht quasi davon aus, die Klammer befinde sich da, wo sie per Y-offset hingebracht wurde, druckt sie aber um extra-offset versetzt).
Ach ja: Da die OttavaBracket im Staff lebt, nicht in der Voice, muss auch Staff in jedem override erwähnt sein (oder der override in nem entsprechenden \with- oder \layout-Block passieren).
*Edit: Das mach ich, damit die ChordNames Platz haben, um ans System heranzurücken.
-
Danke, das klappt jetzt super! :)
Es wäre nicht ich, wenn sich nicht ein neues Problem auftäte :-[: wenn die Ottava-Klammer über mehrere Zeilen geht, dann wirkt sich das extra-offset natürlich auf alle Zeilen aus. Wie schaffe ich es, die Oktavenklammer zu unterbrechen und den Offset neu zu setzen?
So geht es nämlich nicht:
\version "2.19.37"
\language "deutsch"
mymus= { \repeat unfold 3 c4 }
RH = \relative c'' {
< c-1 e-2 > \mymus c \mymus \break
\once \override Staff.OttavaBracket.outside-staff-priority = #'()
\once \override Staff.OttavaBracket.Y-offset = 0
\once \override Staff.OttavaBracket.extra-offset = #'(0 . 9.5)
\ottava #1
c'' \mark \markup {
\column
{
\line { \box \bold A }
\line { \musicglyph #"scripts.segno" }
}
}
\mymus \break
\ottava #0
\once \override Staff.OttavaBracket.outside-staff-priority = #'()
\once \override Staff.OttavaBracket.Y-offset = 0
\once \override Staff.OttavaBracket.extra-offset = #'(0 . 4)
\ottava #1
c \mymus c \mymus
\break c \mymus c \mymus
}
LH = \relative c {
\clef bass
c \mymus c \mymus c \mymus c \mymus c \mymus
}
Akk=\chordmode {
c1 c c c c c
}
\score
{
\new PianoStaff
<<
\new ChordNames ="chords" \Akk
\new Staff="up" \RH
\new Staff ="down" \LH
>>
\layout {
}
}
-
Edit: bevor die eigentliche Antwort kommt, möchte ich noch darauf hinweisen, dass man jetzt in deiner Anwendung schon das Problem von extra-offset sieht: Die Klammern kleben jetzt extrem nah an den darüberliegenden Systemen, weil LilyPond nicht weiß, dass sie da sind. So, jetzt gehts aber los ;)
In diesem Fall muss die Grob-Eigenschaft after-line-breaking gesetzt werden, und zwar wird hier eine Funktion erwartet, die das Grob als Argument bekommt und dann damit was macht. In diesem Fall extra-offset setzen.
Hier erstmal die fertige Lösung:
\version "2.19.37"
\language "deutsch"
mymus= { \repeat unfold 3 c4 }
RH = \relative c'' {
< c-1 e-2 > \mymus c \mymus \break
\once \override Staff.OttavaBracket.outside-staff-priority = #'()
\once \override Staff.OttavaBracket.Y-offset = 0
\once \override Staff.OttavaBracket.after-line-breaking =
#(lambda (grob)
(let* ((orig (ly:grob-original grob))
(pieces (if (ly:grob? orig)
(ly:spanner-broken-into orig) '() )))
(if (or (null? pieces)
(eq? grob (car pieces)))
(ly:grob-set-property! grob 'extra-offset '(0 . 9.8))
(ly:grob-set-property! grob 'extra-offset '(0 . 8.2)))))
\ottava #1
c'' \mark \markup {
\column
{
\line { \box \bold A }
\line { \musicglyph #"scripts.segno" }
}
}
\mymus \break
%\ottava #0
c \mymus c \mymus
\break c \mymus c \mymus
}
LH = \relative c {
\clef bass
c \mymus c \mymus c \mymus c \mymus c \mymus
}
Akk=\chordmode {
c1 c c c c c
}
\score
{
\new PianoStaff
<<
\new ChordNames ="chords" \Akk
\new Staff="up" \RH
\new Staff ="down" \LH
>>
\layout {
}
}
Und hier für Interessierte eine zeilenweise Erklärung:
\once \override Staff.OttavaBracket.after-line-breaking =after-line-breaking ist eine Funktion, die für das Grob (in diesem Fall diese eine OttavaBracket) bzw. seine Teile aufgerufen wird, nachdem LilyPond entschieden hat, wo Zeilenumbrüche gesetzt werden.
#(lambda (grob)Es geht los: die Funktion erhält das Grob als Argument. Ich nenne es „grob“, könnte aber auch z. B. „klammer“ heißen.
(let* ((orig (ly:grob-original grob))let* weist Zwischenergebnisse Namen zu. Hier z. B. wird das Original-Grob (die ungebrochene Klammer (?)) dem Namen orig zugewiesen.
(pieces (if (ly:grob? orig)
(ly:spanner-broken-into orig) '() )))Falls ein Original existiert (also ein Zeilenumbruch stattgefunden hat), wird die Liste der Teile (ansonsten eine leere Liste) dem Namen pieces zugewiesen.
(if (or (null? pieces)
(eq? grob (car pieces)))Falls die Liste der Teile leer ist (wir also nur ein Teil haben) oder unser Argument grob gleich dem ersten Teil ist, …
(ly:grob-set-property! grob 'extra-offset '(0 . 9.8))… setze extra-offset auf '(0 . 9.8), …
(ly:grob-set-property! grob 'extra-offset '(0 . 8.2)))))… ansonsten (wenn grob ein späterer Teil ist) auf '(0 . 8.2).
Ich hoff, das ist so halbwegs klar erklärt, falls nicht und interessiert, einfach nachfragen :)
-
Wow, du machst dir eine Menge Mühe, danke!!! :) :) :)
Ich muss erst alles genau durchlesen, vll. kapiere ich auch was davon ;)
Es dauert bei mir immer etwas, bis es einsickert. Je länger ich mich damit beschäftige, umso besser.
Update: funktioniert phantastisch. Ich habe es auch gleich wieder in eine Funktion umgebaut, wo man die beiden verschiedenen Shifts als Argumente übergibt.
\version "2.19.37"
\language "deutsch"
ottavaShift=
#(define-music-function (1stoffset 2ndoffset)
(pair? pair?)
#{
\once \override Staff.OttavaBracket.outside-staff-priority = #'()
\once \override Staff.OttavaBracket.Y-offset = 0
\once \override Staff.OttavaBracket.after-line-breaking =
#(lambda (grob)
(let* ((orig (ly:grob-original grob))
(pieces (if (ly:grob? orig)
(ly:spanner-broken-into orig) '() )))
(if (or (null? pieces)
(eq? grob (car pieces)))
(ly:grob-set-property! grob 'extra-offset 1stoffset)
(ly:grob-set-property! grob 'extra-offset 2ndoffset))))
#}
)
mymus= { \repeat unfold 3 c4 }
RH = \relative c'' {
< c-1 e-2 > \mymus c \mymus \break
\ottavaShift #'(0 . 10) #'(0 . 8 )
\ottava #1
c'' \mark \markup {
\column
{
\line { \box \bold A }
\line { \musicglyph #"scripts.segno" }
}
}
\mymus \break
c \mymus c \mymus
\break c \mymus c \mymus
}
LH = \relative c {
\clef bass
c \mymus c \mymus c \mymus c \mymus c \mymus
}
Akk=\chordmode {
c1 c c c c c
}
\score
{
\new PianoStaff
<<
\new ChordNames ="chords" \Akk
\new Staff="up" \RH
\new Staff ="down" \LH
>>
\layout {
}
}
Trotzdem verstehe ich nicht ganz, wieso Lily die Staffs so an den oberen Seitenrand klebt, es wäre doch viel Platz nach unten.
-
Ach ja, man kann auch auf jedes Teil einzeln einwirken, nicht nur auf erstes oder „den Rest“. Muss dann natürlich ein bisschen anders aussehen (Stichwort: cond).
-
Du sagst es, ich habe den Fall, dass eine Ottava-Klammer über 5 Zeilen geht und die vierte auch verschoben werden müsste. Ich habe das anders gelöst, indem ich das Rehearsal Mark verschoben habe.
Wenn man sich wirklich guuuut auskennen würde, könnte man eine allgemeine Funktion schreiben, wo man den Namen des Grobs auch noch übergibt
\version "2.19.37"
allgShift=
#(define-music-function (offset context grobname)
(pair? pair? symbol? symbol?)
#{
\once \override $context.$grobname.outside-staff-priority = #'()
\once \override $context.$grobname.Y-offset = 0
\once \override $context.$grobname.extra-offset = $offset
#}
)
So geht's natürlich nicht, man muss wahrscheinlich das unquote-Zeichen verwenden.
-
Du sagst es, ich habe den Fall, dass eine Ottava-Klammer über 5 Zeilen geht und die vierte auch verschoben werden müsste. Ich habe das anders gelöst, indem ich das Rehearsal Mark verschoben habe.
Bräuchtest du noch die allgemeinere Lösung? Könnte ich noch machen. Ist nicht viel Aufwand, aber mach ich nur, wenn Bedarf besteht ;)
Wenn man sich wirklich guuuut auskennen würde, könnte man eine allgemeine Funktion schreiben, wo man den Namen des Grobs auch noch übergibt
Bitteschön:
\version "2.19.37"
allgShift=
#(define-music-function (offset context grobname)
(pair? symbol? symbol?)
#{
\once \override #(list context grobname 'extra-offset) = #offset
#})
\relative {
\allgShift #'(2 . 3) Staff NoteHead
c'
}Ich finds aber nicht viel übersichtlicher, muss ich gestehen.
-
Bräuchtest du noch die allgemeinere Lösung? Könnte ich noch machen. Ist nicht viel Aufwand, aber mach ich nur, wenn Bedarf besteht ;)
Bitte drum, ich bin interessiert. Außerdem lerne ich eine Menge davon. :)
-
\version "2.19.37"
\language "deutsch"
ottavaShift=
#(define-music-function (offsets)
(list?)
#{
\once \override Staff.OttavaBracket.outside-staff-priority = #'()
\once \override Staff.OttavaBracket.Y-offset = 0
\once \override Staff.OttavaBracket.after-line-breaking =
#(lambda (grob)
(let* ((orig (ly:grob-original grob))
(pieces (ly:spanner-broken-into orig)))
(if (null? pieces)
(ly:grob-set-property! grob 'extra-offset (car offsets))
(map (lambda (piece offset)
(ly:grob-set-property! piece 'extra-offset offset))
pieces offsets))))
#})
mymus= { \repeat unfold 3 c4 }
RH = \relative c'' {
< c-1 e-2 > \mymus c \mymus \break
\ottavaShift #'((0 . 9.8) (0 . 8.2) (0 . 5))
\ottava #1
c'' \mark \markup {
\column
{
\line { \box \bold A }
\line { \musicglyph #"scripts.segno" }
}
}
\mymus \break
%\ottava #0
c \mymus c \mymus
\break c \mymus c \mymus
}
LH = \relative c {
\clef bass
c \mymus c \mymus c \mymus c \mymus c \mymus
}
Akk=\chordmode {
c1 c c c c c
}
\score
{
\new PianoStaff
<<
\new ChordNames ="chords" \Akk
\new Staff="up" \RH
\new Staff ="down" \LH
>>
\layout {
}
}Warnung: Diese Funktion ist nicht besonders elegant: Sie wird ja für jeden Teil der OttavaBracket aufgerufen, aber jeder Aufruf setzt die extra-offsets aller Teile, nicht nur für den, für den es aufgerufen wurde. D. h. jeder offset wird mehrmals auf den gleichen Wert gesetzt; ist im Ergebnis nicht sichtbar, aber schön irgendwie auch nicht. Mir fiel aber gerade kein günstigerer Weg ein …
Und wieder mit Erklärung (mir ist dabei aufgefallen, dass das oben unnötig kompliziert war, dieser Test auf ly:grob? ist anscheinend nicht nötig, auch wenn er in dem Code, wo ich die Idee her habe, so gemacht wurde):
\once \override Staff.OttavaBracket.after-line-breaking =
#(lambda (grob)Bis hierhin s. o.
(let* ((orig (ly:grob-original grob))
(pieces (ly:spanner-broken-into orig)))Anscheinend funktioniert ly:spanner-broken-into in jedem Fall; wenns keinen Zeilenumbruch gibt, wird aber eine leere Liste zurückgegeben, keine einelementige.
(if (null? pieces)
(ly:grob-set-property! grob 'extra-offset (car offsets))Falls die Liste leer ist, haben wir keinen Zeilenumbruch und können grob auf den ersten Wert in der offset-Liste setzen.
(map (lambda (piece offset)
(ly:grob-set-property! piece 'extra-offset offset))
pieces offsets))))Ansonsten nehmen wir die beiden Listen pieces (die Teil-Grobs) und offsets her, und laufen einmal gleichzeitig drüber. Nehmen das 1. piece und das 1. offset, mit diesen beiden wird die mittlere Zeile ausgeführt. Dann das 2. piece und das 2. offset, das 3. und das 3. etc.
Um so ein map zu verstehen, helfen vielleicht einfachere Beispiele:\version "2.19.46"
% map mit einer Funktion und einer Liste: wende die Funktion auf alle Element der Liste an
#(write
(map
string-upcase
'("Hallo" "Welt")))
% gleiches, mit selbst geschriebener, namenloser Funktion (λ-Ausdruck)
#(write
(map
(lambda (x) (+ x 5))
'(10 12 14)))
% map mit einer Funktion und zwei Listen: wende die Funktion auf die beiden ersten Elemente an, auf die beiden zweiten, ...
#(write
(map
+
'(1 2 3)
'(4 10 20)))
% wieder mit λ-Ausdruck; wenn eine Liste länger als die andere ist, werden die überzähligen Elemente einfach drangehängt
#(write
(map
(lambda (x y) (+ x y))
'(8 9 10)
'(10 20 30 1000)))
-
Danke für den Code und die umfangreichen Erklärungen! :)
Ein bisschen habe ich glaube ich schon verstanden was map macht. Wenngleich ich immer wieder Schwierigkeiten habe, es in die Praxis umzusetzen.
Update: ich bin total happy mit der slurShiftx-Funktion und lasse Lily jetzt wunderschöne Bögen zeichnen.
-
Ich wollte mich nochmals bedanken, habe das ottavashift-Programm jetzt extensiv verwendet (ottava geht über 4 Seiten), und es ist sehr sehr nützlich!