Deutsches Lilypond Forum (Archiv)

Allgemein => Fragen zu Funktionen => Thema gestartet von: harm6 am Montag, 27. Juni 2011, 23:50

Titel: building and aligning custom-dynamics
Beitrag von: harm6 am Montag, 27. Juni 2011, 23:50
Hallo,

bei meinen weiteren Recherchen zum Thread left-align in scheme markup? (https://liarchiv.joonet.de/index.php?topic=902.0)  habe ich das markup-command dynamic-string hier (http://git.savannah.gnu.org/cgit/opus-libre.git/tree/bin/markup-commands.scm) gefunden. Damit sind Weiterungen möglich, die mich veranlaßt haben, einen neuen Thread anzufangen, um einige davon vorzustellen
Dieses markup-command spaltet einen gegebenen String automatisch in die Schrift dynamic und normal-text italic auf. Voraussetzung ist eine Syntax, die die dynamic-Teile von den normalen mittels Tiefstrich separiert.
Alles was danach kommt ist meine persönliche Auffassung wie man am besten damit umgeht (andere Vorgehensweisen sind möglich und da ich den Code recht ausführlich kommentiert habe leicht umzusetzen, hoffe ich zumindest  ;)).


Ich finde custom-dynamics sind am besten in einer alist aufgehoben, aus der man sie einfach abruft. Insofern habe ich my-dyn-alist definiert, sowie assocDynAlist und newDyn, um besser mit ihr umzugehen.

Die Definition makeAlistDynamicScript erstellt ein left-aligned custom-dynamic. makeDynamicScript macht dasselbe mit einem beliebigen Text (in der richtigen Syntax).
Die Definition myLeftDynamic ist eigentlich überflüssig, sie ist lediglich die  Verbesserung meiner Funktion aus dem anderen Thread.
Die Funktion myDynamic erstellt custom-dynamics per alist Aufruf, wahlweise left-aligned oder zentriert.

Darüber hinaus kann man natürlich auch ein echtes markup erstellen mit den kompletten üblichen Befehlsmöglichkeiten. Für right-aligned custom-dynamics bevorzuge ich diese Vorgehensweise im Moment, da es mir noch nicht gelungen ist, ein richtig gutes right-align in eine der obigen Definitionen einzubauen. (Es gibt zwar das LSR-Snippet 739 (http://lsr.dsi.unimi.it/LSR/Item?id=739), aber es ist beschränkt auf höchstens zwei getrennte Strings).

Zur Anwendung:
Die dynamic-script Definitionen benötigen die übliche postfix-Syntax für dynamics.
Die Funktionen benötigen -\ als Aufruf sonst werden sie der nächsten Note zugeordnet.
Die String-Syntax ist unbedingt zu beachten.

\version "2.14.1"

\paper {
        line-width = 120
        indent = 0
}

% http://codereview.appspot.com/2220041/patch/12001/13007
% Charset definitions (completing standard guile defs)

#(define-public (char-punctuation? ch)
 (char-set-contains? char-set:punctuation ch))

#(define-public char-set:dynamics
 (char-set #\f #\m #\p #\r #\s #\z))

% http://git.savannah.gnu.org/cgit/opus-libre.git/tree/bin/markup-commands.scm
% by Valentin Villenave
 
#(define-markup-command (dynamic-string layout props str) (string?)
  #:category font
  "
@cindex dynamics, composite
@cindex dynamics, mixed with text

Print a string using the dynamic font only when appropriate.
Words may be separated with @code{_}; dynamic-style characters
will only be used in words that contain no other letter than
@b{f}, @b{m}, @b{p}, @b{r}, @b{s} and @b{z}, and punctuation
marks.  Regular spaces are allowed inside words.

@lilypond[verbatim,quote]
\\markup {
  \\dynamic-string #\"mp,_quasi_mf_ma più dolce.\"
}
@end lilypond"
  (let ((composite-chars (char-set-union
                          char-set:dynamics
                          char-set:whitespace
                          char-set:punctuation))
        (split (lambda (s) (string-index s #\_ )))
        (str-list '())
        (dyn-markup (lambda (s)       
                      (make-whiteout-markup ;;-a
                        (make-dynamic-markup s)))) ;;-a
                        ;(make-dynamic-markup s))) ;;+b
        (text-markup (lambda (s)
                       (make-whiteout-markup
                         (make-normal-text-markup
                           (make-italic-markup s))))))
    (do ((current-str (string-append str "_")))
        ((not (split current-str)))
      (begin
        (set! str-list
              (append str-list (list
                                (string-take current-str (split current-str)))))
        (set! current-str
              (string-drop current-str (+ (split current-str) 1)))))
    (interpret-markup layout props
                      (make-line-markup
                       (map (lambda (word)
                              (if (string-every composite-chars word)
                                  (if (string-every char-set:dynamics word)
                                      (dyn-markup word)
                                      (let ((word-lst (string->list word)))
                                        (make-concat-markup
                                         (map (lambda (ch)
                                                (let ((print-ch (string ch)))
                                                  (if (char-punctuation? ch)
                                                      (text-markup print-ch)
                                                      (dyn-markup print-ch))))
                                              word-lst))))
                                  (text-markup word)))
                            str-list)))))
 
% Additionals by Harm

#(define my-dyn-alist '(
("pptop" . "pp_<_p_>_pp_etc . . .")
("ffdolcef" . "ff_dolce >_f")
("pleggierodolce" . "p,_leggiero e dolce")
("dolcecantabile" . "dolce e cantabile")
("fcantabile" . "f,_ma cantabile")
("pquasieco" . "p,_quasi eco")
("subitoff" . "subito_ff")
("mpquasimf" . "mp_,quasi_mf_ma più dolce.")
("fffmarcato" . "fff_marcato sempre")
("madolcecant" . "ma dolce e cantabile")
))


#(define (assocDynAlist name)
"Aus my-dyn-alist wird der 2. Eintrag einer Zeile ausgelesen!
Die Zeile wir via name angesteuert!"
     (assoc-ref my-dyn-alist name))

#(define-markup-command (newDyn layout props name)(string?)
"newDyn kann den 2. Eintrag einer Zeile aus my-dyn-alist mit dynamic-string verarbeiten!
Die Zeile wir via name angesteuert!"
     (interpret-markup
        layout props (markup #:dynamic-string (assocDynAlist name))))

% nach: http://codereview.appspot.com/2220041/patch/12001/13005

#(define (makeAlistDynamicScript name)
"Mittels alist-Aufruf via newDyn wird eine neues left-aligned custom-Dynamic möglich"
   (make-music 'AbsoluteDynamicEvent
'tweaks
     (list (cons 'X-offset -1.5))
'text
  (markup #:newDyn name)))

#(define (makeDynamicScript text)
"Eine neues left-aligned custom-Dynamic mit beliebigem Text (in der für dynamic-string
nötigen Syntax) wird möglich"
   (make-music 'AbsoluteDynamicEvent
'tweaks
     (list (cons 'X-offset -1.5))
'text
  (markup #:dynamic-string text)))
 
mpquasimf = #(makeAlistDynamicScript "mpquasimf")
dffs = #(makeDynamicScript "Das-soll_ff_sein!!")

myLeftDynamic =
#(define-music-function (parser location name)(string?)
     (make-music                                             
       'AbsoluteDynamicEvent
       
       'tweaks
         ;; calculate centering for text
         (list (cons 'X-offset -1.5))
       'text
         (markup #:newDyn name
         )))
     
myDynamic =
#(define-music-function (parser location name align)(string? integer?)
"Diese Funktion erstellt mittels alist-Aufruf via newDyn neue custom-Dynamics. Man hat
die Möglichkeit linksbündig (#'-1) oder zentriert (#'0) auszuwählen (alle Zahlen >0 führen zur
zentrierter Ausgabe).
Syntax: -\\myDynamic <name> #'-1"

     (make-music
       'AbsoluteDynamicEvent
       
       'tweaks
         ;; calculate centering for text
         (cond
               ((< align 0) (list (cons 'X-offset -1.5)))
               ;(else (list (cons 'X-offset 0 )))
               )
       'text
         (markup #:newDyn name
         )))

%------------------------------ Test -------------------------------------------

\markup { \fill-line { \bold "Dynamic-Scripts" \null} }

\relative c' {
        s1 a'\mpquasimf \break
        s b\dffs
}

\markup \fill-line{\column  {\vspace #2 \bold "myDynamic und myLeftDynamic" } \null}

\relative c''     
{
        \override Staff.TimeSignature #'stencil = ##f
       
a4 a bes-\myDynamic "pptop" #'-1 a|
a a bes-\myDynamic "subitoff" #'-1 a |
a bes a a |\break
a a bes-\myDynamic "ffdolcef" #'0 a |
a bes-\myLeftDynamic "ffdolcef" a a |                 
a a a a |\break           
a a bes-\myDynamic "pleggierodolce" #'-1 a |
a a a a |                 
a a a a |\break           
a a bes-\myDynamic "dolcecantabile" #'0 a |
a a a a|                   
a a a a |\break           
a a bes-\myDynamic "fcantabile" #'-1 a |
a a a a |                 
a a a a |
}

\markup \fill-line{\column {\vspace #2 \bold "markup" } \null}

\relative c'' {
        \override TextScript #'staff-padding = #1
        %\textLengthOn
gis1_\markup { \newDyn #"mpquasimf"} a
gis a_\markup { \translate #'(1.3 . 0) \right-align \newDyn #"subitoff"} \break 
gis a_\markup { \center-align \newDyn #"pleggierodolce"}
gis_\markup { \newDyn #"dolcecantabile"} a\break
gis_\markup { \newDyn #"fcantabile"} a   
gis_\markup { \newDyn #"pquasieco"} a\break
gis_\markup { \left-column \fontsize #'-1 {\newDyn #"pptop"  \newDyn #"madolcecant" }}a
gis_\markup { \newDyn #"fffmarcato"} a
}

Gruß,
  Harm

P.S. Wenn man \vspace #'2 aus dem Code rausnimmt sollte er auch in 2.12.3 kompilierbar sein. Hoffe ich!  ;)
P.P.S. Ich habe den Titel des Threads in Englisch geschrieben, da es mich schon oft geärgert hat, daß eine google-Suche die deutschen Beiträge nicht oder nur unvollkommen liefert.
Titel: Re: building and aligning custom-dynamics
Beitrag von: harm6 am Montag, 11. Juli 2011, 01:14
Hallo,

hier das vorläufige Ende meiner Grübeleien:

Alle folgenden Definitionen beruhen auf dem dynamic-string-command.
Dynamic-string benötigt eine Syntax, in der die Elemente, die mit dynamic font dargestellt werden sollen, durch Tiefstriche "_"  abgesetzt sind. Zusätzlich habe ich ein feature eingebaut mit dem die Zeichen "<" und ">" gestreckt werden. Damit das funktioniert sind wieder Tiefstriche erforderlich.
Z.B.:  "pp_<_p_>_pp_etc . . ."

Immerwieder genutzte, eigene dynamics in einer alist zu speichern ist praktisch. Andererseits ist es sinnvoll einen beliebigen Text direkt verarbeiten zukönnen. Insofern habe ich mich entschlossen immer zwei Varianten zu definieren.

Dynamic-scripts
:
sind dynamic-script-Definitionen für beliebigen Text (Syntax beachten!)

sind dynamic-script-Definitionen für den alist-Aufruf

Alle dynamic-script-Definitionen haben IMHO den Nachteil, daß das neue custom-Dynamic  noch extra definiert werden muß. Z.B. subitoF = #(dynRight "subito_f"). Der Vorteil ist natürlich, daß die übliche Postfix-Syntax in der Anwendung erhalten bleibt z.B.: bes\attFFFF

Funktionen:

ist eine Funktion für beliebigen Text (Syntax beachten!)

ist eine Funktion für den alist-Aufruf

Die Funktionen benötigen ein "-" Zeichen in der Anwendung und weichen somit von der üblichen Postfix-Syntax für Dynamics ab. Sie brauchen zusätzlich eine Angabe für die Ausrichtung: #-1 für left-aligned, #0 für centered #1 für right-aligned.
Z.B.: a-\newDyn #-1 "das soll_fff_sein!!_fff"

Anmerkungen:

Sowohl bei den scripts als auch bei den Funktionen findet kein echtes left- oder right-align statt (ich habe nur der Einfachheit wegen so formuliert). Tatsächlich habe ich eine Verschiebung und Anpassung geschrieben, je nachdem wieviel Buchstaben im ersten vor allem aber im letzten dynamischen Ausdruck vorkommen. (definiert ist ein unterschiedliches Verhalten bis zur Obergrenze von 6 Buchstaben z.B.: sffffz, kennt jemand ein Zeichen mit mehr als 6 Buchstaben?).
Das gestreckte "<"-Zeichen wird als cresc.-Ersatz benutzt. (">" für decresc.)

newDynLeft (für alist-Aufruf!)
newDynRight (für alist-Aufruf!)
sind markup-commands, die ich als hauptsächlich als Werkzeuge benutzt habe. In einem gewöhnlichen markup sind sie aber auch einsetzbar.

Es wäre schön, wenn ihr diese Definitionen mal ausprobieren und eventuelle Probleme melden könntet. Bislang habe ich nur in Kurzbeispielen getestet.

Gruß,
  Harm

P.S.
@kilgore Ich hoffe Du hast Dein update gemacht, denn diese Definitionen funktionieren nicht auf 2.12.3