Allgemein > Fragen zu Funktionen
Phrasierungsbögen an Text ausrichten / Custom TextSpannerEngraver
xr:
@harm,
ich habe versucht, dein Beispiel des bend-engravers zu verstehen, vor allem bend-grob-defs.ly
Gleichzeitig habe ich noch dieses Beispiel gefunden:
https://github.com/starrynte/lilypond/blob/92d671669c1aa7e54655c118b37c4a2f191aaded/input/regression/scheme-text-spanner.ly
Die beiden sind sich sehr ähnlich.
Ich habe zunächst einmal versucht, einen zweiten Engraver zu entwerfen und einfache Umbenennungen vorzunehmen. Das ist leider direkt gescheitert.
Wenn ich versuche, das text-spanner-event umzubenennen, bekomme ich den Fehler: Programmierfehler: Not a music type
( Ich habe SchemeTextSpanEvent in SchemeTextSpanEventB umbenannt. github Zeilen 68, 172, 175,
oder in deiner Datei: BendSpanEvent in BendSpanEventA. Zeilen 131, 353, 356)
Ich habe keine Stelle gesehen, an der der Name nochmals auftauchen würde. Warum geht das nicht?
Wenn ich mir music-descriptions und all-grob-descriptions anzeigen lasse, scheinen der Grob und der Event-Spanner eingetragen worden zu sein.
Könntest du mir da nochmal Auskunft geben?
Gruß,
Xaver
harm6:
--- Zitat ---ich habe versucht, dein Beispiel des bend-engravers zu verstehen, vor allem bend-grob-defs.ly
Gleichzeitig habe ich noch dieses Beispiel gefunden:
https://github.com/starrynte/lilypond/blob/92d671669c1aa7e54655c118b37c4a2f191aaded/input/regression/scheme-text-spanner.ly
Die beiden sind sich sehr ähnlich.
--- Ende Zitat ---
Der schemeTextSpannerEngraver ist aus unseren regression-tests. Der direkte link:
lilypond.org/doc/v2.19/input/regression/6c/lily-35f36acf.ly
Der link, den Du oben angegeben hast ist glaub' ich ein backup.
Und ja, mein BendSpannerEngraver ist der kaum veränderte schemeTextSpannerEngraver.
--- Zitat ---Ich habe zunächst einmal versucht, einen zweiten Engraver zu entwerfen und einfache Umbenennungen vorzunehmen. Das ist leider direkt gescheitert.
Wenn ich versuche, das text-spanner-event umzubenennen, bekomme ich den Fehler: Programmierfehler: Not a music type
--- Ende Zitat ---
Du müsstest SchemeTextSpanEvent in SchemeTextSpanEventB umbenennen und scheme-text-span-event in scheme-text-span-event-b.
Das eine ist class, das andere type.
Siehe:
--- Zitat ---#(define scheme-event-spanner-types
'(
(SchemeTextSpanEvent
. ((description . "Used to signal where scheme text spanner brackets
start and stop.")
(types . (post-event scheme-text-span-event span-event event))
))
))
--- Ende Zitat ---
Da kommen beide vor. Die Namen müssen passen!
--- Zitat ---Könntest du mir da nochmal Auskunft geben?
--- Ende Zitat ---
Ich hab' ne zeitlang nicht geantwortet, da mir eine wirklich zündende Idee nicht kommen will. Sobald ich was habe werd' ich mich melden.
Eine Schwierigkeit sehe ich jedoch jetzt schon: der zu schaffende spanner muß Deinen Beispielen nach cross-context funktionieren, immer eine heikle Sache...
Gruß,
Harm
xr:
Herzlichen Dank für die Antwort. Da wäre ich allein nie drauf gekommen!
Meine momentane Idee ist, Text Spanner zu benutzen, um die Punkte zu setzen, an denen die Bögen anfangen, enden und evtl. nur durchlaufen sollen. Das Problem bei den Spannern ist allerdings, dass, soweit ich es verstehe, von jedem Typ immer nur je einer gleichzeitig genutzt werden kann. Bzw. dass ein Spanner automatisch endet, sobald ein neuer begonnen wird.
Daher brauche ich mehrere. Und da ich die Funktionen von Lilypond nicht einschränken will - man könnte ja auch unterschiedliche Spanner "mißbrauchen", also Text-, Slur- und Phrasing beispielsweise, die dann anderweitig aber nicht mehr zur Verfügung stünden - , will ich benutzerdefinierte Spanner schreiben. Der PhrasingSlur fällt einstweilen aus, da mir eine Übersetzung aus C++ noch zu langwierig ist. Deswegen versuch ich mich jetzt mal am TextSpanner.
Zwei Fragen bezüglich der Scheme Syntax habe ich noch. Vor allem zu ersterer habe ich gar keine Einträge gefunden:
- Was genau macht dieses Hochkomma (Gravis) vor einer Klammer? Es wandelt wohl Nachfolgendes in eine Liste um. Aber gibts da Regeln?
- Wofür steht das Komma in folgender Konstrukion: (direction . ,UP) Fließkomma?
Cross-Voice: Du kennst bestimmt diesen Beitrag:
http://lilypondblog.org/2016/08/google-summer-of-code-2016-cross-voice-spanners/
Allerdings funktioniert sein angegebener Code in 2.19.54 bei mir entweder nicht, oder man sieht keine Änderung gegenüber gewöhnlicher Eingabe.
Gruß,
Xaver
P.S: Bei dem Fehler Not a music type hatte ich keine Möglichkeit, irgendeine Ausgabe zu bekommen. Auch kein #(write 'Fehler) in den Anfangszeilen des Codes wurde ausgegeben. Gibt es da noch mitteilsamere Lilipond Varianten?
harm6:
--- Zitat ---Meine momentane Idee ist, Text Spanner zu benutzen, um die Punkte zu setzen, an denen die Bögen anfangen, enden und evtl. nur durchlaufen sollen. Das Problem bei den Spannern ist allerdings, dass, soweit ich es verstehe, von jedem Typ immer nur je einer gleichzeitig genutzt werden kann. Bzw. dass ein Spanner automatisch endet, sobald ein neuer begonnen wird.
--- Ende Zitat ---
Nicht ganz.
Siehe:
http://lilypond.org/doc/v2.19/Documentation/changes/index.html
Such nach:
--- Zitat ---There is a new command \= for specifying the spanner-id for simultaneous slurs and phrasing slurs.
--- Ende Zitat ---
--- Zitat ---Zwei Fragen bezüglich der Scheme Syntax habe ich noch. Vor allem zu ersterer habe ich gar keine Einträge gefunden:
- Was genau macht dieses Hochkomma (Gravis) vor einer Klammer? Es wandelt wohl Nachfolgendes in eine Liste um. Aber gibts da Regeln?
- Wofür steht das Komma in folgender Konstrukion: (direction . ,UP) Fließkomma?
--- Ende Zitat ---
Siehe:
https://liarchiv.joonet.de/index.php?topic=1762.msg9753#msg9753
--- Zitat ---Cross-Voice: Du kennst bestimmt diesen Beitrag:
http://lilypondblog.org/2016/08/google-summer-of-code-2016-cross-voice-spanners/
Allerdings funktioniert sein angegebener Code in 2.19.54 bei mir entweder nicht, oder man sieht keine Änderung gegenüber gewöhnlicher Eingabe.
--- Ende Zitat ---
Aufgrund des dortigen C++ codes ist eine Neukompilierung von LilyPond nötig. Hab ich nie getestet.
--- Zitat ---Bei dem Fehler Not a music type hatte ich keine Möglichkeit, irgendeine Ausgabe zu bekommen. Auch kein #(write 'Fehler) in den Anfangszeilen des Codes wurde ausgegeben. Gibt es da noch mitteilsamere Lilipond Varianten?
--- Ende Zitat ---
Nicht das ich wüsste.
Die Ausgabe einer sinvollen und nützlichen Fehlermeldung ist eine Kunst.
LilyPond ist da noch stark verbesserungsfähig ...
Allerdings ist man beim Vorhaben ein neues grob zu erschaffen auch tief, tief in Herz und Gehirn von LilyPond...
Gruß,
Harm
xr:
--- Zitat ---Nicht ganz.
Siehe:
http://lilypond.org/doc/v2.19/Documentation/changes/index.html
Such nach:
--- Ende Zitat ---
Hätte ich das mal früher gesehen, dann hätte ich den gestrigen Abend anders verbracht.
Damit sind ja richtig komplizierte Konstruktionen möglich.
--- Code: ---\version "2.19.54"
\fixed c' {
c1\=3^(\=5( <c~ f\=1( a\=4( g'^\=2( >2 <c e\=1) > < d,\=3) e'\=4)\=5) > r\=2)
}
--- Ende Code ---
Wahrscheinlich werde ich das auch als Lösung weiterverfolgen.
Mein Abend und Teile meines Morgens sind jetzt allerdings für folgendes eingesetzt worden:
Ein Template zum Erstellen von TextSpannerEngravern.
Beispieldatei:
--- Code: ---\version "2.19.52"
%% Example for creating multiple custom text spanners
%% Based on:
% http://lilypond.org/doc/v2.18/input/regression/collated-files.html
% look for:
% ‘scheme-text-spanner.ly’
custom-engraver = "Hallo"
% rename path to your file, which holds the engraver code
\include "template-scheme-text-spanner-engraver2.ly"
custom-engraver = "Welt"
\include "template-scheme-text-spanner-engraver2.ly"
custom-engraver = "A"
\include "template-scheme-text-spanner-engraver2.ly"
\layout {
\context {
\Global
\grobdescriptions #all-grob-descriptions
}
\context {
\Voice
\consists #HalloTextSpanner
\consists #WeltTextSpanner
\consists #ATextSpanner
}
}
\relative {
\override HalloTextSpanner.to-barline = ##f
\override HalloTextSpanner.bound-details.left.text = #"hal"
\override HalloTextSpanner.bound-details.right.text = #"lo"
\override WeltTextSpanner.bound-details.left.text = #"we"
\override WeltTextSpanner.bound-details.right.text = #"lt"
\override ATextSpanner.bound-details.left.text = #"A"
\override ATextSpanner.bound-details.right.text = #"A"
a4 b\hallo-start c\welt-start d
a4 b c d
a4 \a-start b c\hallo-stop d \welt-stop \break
a4\hallo-start \welt-start b d \a-stop c
a4 b\hallo-stop c d \welt-stop
a1
}
--- Ende Code ---
Und der folgende Code muss in eine andere Datei gespeichert werden und der Pfad in obiger Datei bei \include entsprechend angepaßt werden.
--- Code: ---%% Example for creating multiple custom text spanners
%% Based on:
% http://lilypond.org/doc/v2.18/input/regression/collated-files.html
% look for:
% ‘scheme-text-spanner.ly’
\version "2.19.54"
%% define vars to be used to formate text
#(define ev-class-name 0)
#(define ev-type-name 0)
#(define grob-def-name 0)
#(define engraver-name 0)
#(define (create-custom-engraver name)
(set! ev-class-name (string-append (string-downcase name) "-text-span-event"))
(set! ev-type-name (string-append name "TextSpanEvent"))
(set! grob-def-name (string-append name "TextSpanner"))
(set! engraver-name (string-append name "TextSpannerEngraver" ))
)
#(create-custom-engraver custom-engraver)
#(define template-list (list "
(begin
(define-event-class '" ev-class-name " 'span-event)
(define (add-grob-definition grob-name grob-entry)
(let* ((meta-entry (assoc-get 'meta grob-entry))
(class (assoc-get 'class meta-entry))
(ifaces-entry (assoc-get 'interfaces meta-entry)))
(set-object-property! grob-name 'translation-type? ly:grob-properties?)
(set-object-property! grob-name 'is-grob? #t)
(set! ifaces-entry (append (case class
((Item) '(item-interface))
((Spanner) '(spanner-interface))
((Paper_column) '((item-interface
paper-column-interface)))
((System) '((system-interface
spanner-interface)))
(else '(unknown-interface)))
ifaces-entry))
(set! ifaces-entry (uniq-list (sort ifaces-entry symbol<?)))
(set! ifaces-entry (cons 'grob-interface ifaces-entry))
(set! meta-entry (assoc-set! meta-entry 'name grob-name))
(set! meta-entry (assoc-set! meta-entry 'interfaces
ifaces-entry))
(set! grob-entry (assoc-set! grob-entry 'meta meta-entry))
(set! all-grob-descriptions
(cons (cons grob-name grob-entry)
all-grob-descriptions))))
(add-grob-definition
'" grob-def-name
" `(
(bound-details . ((left . ((Y . 0)
(padding . 0.25)
(attach-dir . ,LEFT)
))
(left-broken . ((end-on-note . #t)))
(right . ((Y . 0)
(padding . 0.25)
))
))
(dash-fraction . 0.2)
(dash-period . 3.0)
(direction . ,UP)
(font-shape . italic)
(left-bound-info . ,ly:line-spanner::calc-left-bound-info)
(outside-staff-priority . 350)
(right-bound-info . ,ly:line-spanner::calc-right-bound-info)
(staff-padding . 0.8)
(stencil . ,ly:line-spanner::print)
(style . dashed-line)
(meta . ((class . Spanner)
(interfaces . (font-interface
line-interface
line-spanner-interface
outside-staff-interface
side-position-interface))))))
(define scheme-event-spanner-types
'(
(" ev-type-name
" . ((description . \"Used to signal where scheme text spanner brackets
start and stop.\")
(types . (post-event " ev-class-name " span-event event))
))
))
(set!
scheme-event-spanner-types
(map (lambda (x)
(set-object-property! (car x)
'music-description
(cdr (assq 'description (cdr x))))
(let ((lst (cdr x)))
(set! lst (assoc-set! lst 'name (car x)))
(set! lst (assq-remove! lst 'description))
(hashq-set! music-name-to-property-table (car x) lst)
(cons (car x) lst)))
scheme-event-spanner-types))
(set! music-descriptions
(append scheme-event-spanner-types music-descriptions))
(set! music-descriptions
(sort music-descriptions alist<?))
(define (add-bound-item spanner item)
(if (null? (ly:spanner-bound spanner LEFT))
(ly:spanner-set-bound! spanner LEFT item)
(ly:spanner-set-bound! spanner RIGHT item)))
(define (axis-offset-symbol axis)
(if (eqv? axis X) 'X-offset 'Y-offset))
(define (set-axis! grob axis)
(if (not (number? (ly:grob-property grob 'side-axis)))
(begin
(set! (ly:grob-property grob 'side-axis) axis)
(ly:grob-chain-callback
grob
(if (eqv? axis X)
ly:side-position-interface::x-aligned-side
side-position-interface::y-aligned-side)
(axis-offset-symbol axis)))))
(define " engraver-name "
(lambda (context)
(let ((span '())
(finished '())
(event-start '())
(event-stop '()))
(make-engraver
(listeners ((" ev-class-name " engraver event)
(if (= START (ly:event-property event 'span-direction))
(set! event-start event)
(set! event-stop event))))
(acknowledgers ((note-column-interface engraver grob source-engraver)
(if (ly:spanner? span)
(begin
(ly:pointer-group-interface::add-grob span 'note-columns grob)
(add-bound-item span grob)))
(if (ly:spanner? finished)
(begin
(ly:pointer-group-interface::add-grob finished 'note-columns grob)
(add-bound-item finished grob)))))
((process-music trans)
(if (ly:stream-event? event-stop)
(if (null? span)
(ly:warning \"You're trying to end a scheme text spanner but you haven't started one.\")
(begin (set! finished span)
(ly:engraver-announce-end-grob trans finished event-start)
(set! span '())
(set! event-stop '()))))
(if (ly:stream-event? event-start)
(begin (set! span (ly:engraver-make-grob trans '" grob-def-name " event-start))
(set-axis! span Y)
(set! event-start '()))))
((stop-translation-timestep trans)
(if (and (ly:spanner? span)
(null? (ly:spanner-bound span LEFT)))
(ly:spanner-set-bound! span LEFT
(ly:context-property context 'currentMusicalColumn)))
(if (ly:spanner? finished)
(begin
(if (null? (ly:spanner-bound finished RIGHT))
(ly:spanner-set-bound! finished RIGHT
(ly:context-property context 'currentMusicalColumn)))
(set! finished '())
(set! event-start '())
(set! event-stop '()))))
((finalize trans)
(if (ly:spanner? finished)
(begin
(if (null? (ly:spanner-bound finished RIGHT))
(ly:spanner-set-bound! finished RIGHT
(ly:context-property context 'currentMusicalColumn)))
(set! finished '())))
(if (ly:spanner? span)
(begin
(ly:warning \"I think there's a dangling scheme text spanner :-(\")
(ly:grob-suicide! span)
(set! span '()))))))))
)
"))
%% make one long string from text-list
#(define template-txt (string-concatenate template-list))
%% evaluate expression
#(define tmp (eval (read (open-input-string template-txt))
(current-module)))
%% create Variable, which holds the Engraver -> <Name>TextSpanner
#(module-define! (current-module) (string->symbol grob-def-name)
(eval (read (open-input-string engraver-name))(current-module)))
%% Create Variable which holds the start command of the engraver -> <name>-start
#(define var (string-append (string-downcase custom-engraver) "-start"))
start = #(make-span-event (string->symbol ev-type-name) START)
#(module-define! (current-module)
(string->symbol var)
start)
%% Create Variable which holds the stop command of the engraver -> <name>-stop
#(define var (string-append (string-downcase custom-engraver) "-stop"))
start = #(make-span-event (string->symbol ev-type-name) STOP)
#(module-define! (current-module)
(string->symbol var)
start)
--- Ende Code ---
Das ganze ist nur so lang und umständlich geworden, weil ich im make-engraver den Klassennamen scheme-text-span-event nicht durch eine Variable ersetzen konnte:
(listeners ((scheme-text-span-event engraver event)
Navigation
[0] Themen-Index
[#] Nächste Seite
[*] Vorherige Sete
Zur normalen Ansicht wechseln