Autor Thema: Artikulationszeichen selbst entwerfen - wie? (gelöst)  (Gelesen 1058 mal)

Manuela

  • Gast
Artikulationszeichen selbst entwerfen - wie? (gelöst)
« am: Freitag, 5. August 2016, 17:49 »
Hi,

ich möchte ein eigenes Artikulationszeichen definieren, derzeit behelfe ich mir folgendermaßen:

\version "2.19.37"

#(define-markup-command (softnote layout props) ()
   (interpret-markup layout props
     (markup #:stencil
       (ly:stencil-translate-axis
        (ly:stencil-add
         (make-circle-stencil 0.6 0.2 #f)
         (ly:stencil-in-color
          (make-filled-box-stencil '(-1 . 1) '(0 . 1.3))
          1 1 1 )
         )
        0.7 X)
       )))

soft = \markup \softnote

{ c'' -\soft }

Diese Lösung hat natürlich Nachteile.

Ich habe auch CodeSnippet 858 studiert, http://lsr.di.unimi.it/LSR/Item?id=858 und meinen Stencil eingebaut

#(define (bold-tenuto-script-stencil grob)
   (let*
    ((scale (magstep (ly:grob-property grob 'font-size 0)))
     (dir (ly:grob-property grob 'direction 0))
     (script-stencil (ly:grob-property grob 'script-stencil))
     (tenuto-width 0.25) ;;; alter this value to modify the line width of the tenuto
     (tenuto-length 1.5) ;;; alter this value to modify the line length of the tenuto
     (tl (* -0.5 tenuto-length))
     (tr (* 0.5 tenuto-length))
     (my-sil (ly:stencil-scale
              (ly:stencil-translate-axis
               (ly:stencil-add
                (make-circle-stencil 0.6 0.2 #f)
                (ly:stencil-in-color
                 (make-filled-box-stencil '(-1 . 1) '(0 . 1.3))
                 1 1 1 )) 0.7 X) scale scale)))
    (if (and (pair? script-stencil) (pair? (cdr script-stencil)))
        (let* ((rv (cdr script-stencil))
               (script-type (if (<= dir 0) (car rv) (cdr rv))))
          (cond ((equal? script-type "tenuto")
                 my-sil)
            ((or (equal? script-type "uportato") (equal? script-type "dportato"))
             my-sil)
            (else (ly:script-interface::print grob)))
          )
        (ly:script-interface::print grob))))

% define globally
\layout {
  \context {
    \Voice
    \override Script.stencil = #bold-tenuto-script-stencil
  }
}

Das würde auch gehen.
Es gibt auch ein Zeichen, das meinen Vorstellungen (vermutlich) entspricht, U+1D55 in der Windows-Zeichentabelle, ein unteres halbes kleines O, leider weiß ich nicht, wie ich das in das Script einbauen kann.
« Letzte Änderung: Dienstag, 9. August 2016, 14:13 von Manuela »

fugenkomponist

  • Gast
Re: Artikulationszeichen selbst entwerfen - wie?
« Antwort #1 am: Freitag, 5. August 2016, 18:40 »
Diese Lösung hat natürlich Nachteile.
Ja, z. B. dass es keine Artikulation erzeugt, sondern ein TextScript und damit die Positionierung entsprechend ist.
Zitat
Es gibt auch ein Zeichen, das meinen Vorstellungen (vermutlich) entspricht, U+1D55 in der Windows-Zeichentabelle, ein unteres halbes kleines O, leider weiß ich nicht, wie ich das in das Script einbauen kann.
Das Zeichen dort hat eine ganz andere Bedeutung. Was du ja eigentlich willst, ist, das als unbetont zu markieren (Schönberg? ;) ) Das SMuFL (Standard Music Font Layout) hat U+E4B8 belegt (Quelle). Feta/LilyPond kennt viele dieser Zeichen nicht, aber der Font Bravura. Dieser Post vom LilyPond-Blog beschreibt, wie es genutzt werden kann. Alternativ kann man das Zeichen auch selbst zeichnen in PostScript.

Was jedenfalls zu tun ist, um eine „echte“ Artikulation zu erzeugen: Wirklich ein ArticulationEvent erzeugen (im folgenden Code z. B. eine Fermate) und den stencil per \tweak überschreiben. Hier mal eine Version mit selbst gezeichnetem Zeichen (wenn dir die Form so nicht gefällt, sag bescheid, das kann man ändern):
\version "2.19.37"

soft =
-\tweak stencil
#(lambda (grob)
   (grob-interpret-markup grob
     #{
       \markup
       \with-dimensions #'(-0.7 . 0.7) #'(-0.7 . 0)
       \postscript
       #"0.15 setlinewidth -0.7 0 moveto 0 0 0.7 180 0 arc stroke"
     #}))
\fermata

{ c''-\soft }
Die Fermate (\fermata) kannst du durch andere Artikulationen (z. B. -- oder ->) ersetzen, um eine andere Positionierung zu bekommen. Alternativ könnte man nen eigenen articulation-type definieren ;) Und wenn du möchtest, kann man davon unabhängig sogar im MIDI leiser werden …

Edit: Und wenn du es brauchst, kann man den stencil auch noch so umbauen, dass sich das Zeichen umdreht, wenn es unter der Note steht.
2. Edit: Das sähe dann so aus:\version "2.19.37"

soft =
-\tweak stencil
#(lambda (grob)
   (grob-interpret-markup grob
     (if (eq? UP (ly:grob-property grob 'direction))
         #{
           \markup
           \with-dimensions #'(-0.7 . 0.7) #'(-0.7 . 0)
           \postscript
           #"0.15 setlinewidth -0.7 0 moveto 0 0 0.7 180 0 arc stroke"
         #}
         #{
           \markup
           \with-dimensions #'(-0.7 . 0.7) #'(0 . 0.7)
           \postscript
           #"0.15 setlinewidth 0.7 0 moveto 0 0 0.7 0 180 arc stroke"
         #})))
\fermata

{ c''\soft c''_\soft c''^\soft }
« Letzte Änderung: Freitag, 5. August 2016, 18:47 von fugenkomponist »

Manuela

  • Gast
Re: Artikulationszeichen selbst entwerfen - wie?
« Antwort #2 am: Freitag, 5. August 2016, 18:49 »
Danke, das ist extra-genial!  :)

Meine KLin malt das Zeichen immer in meine Noten, wenn ich eine Note betone, die nicht betont gehört.
« Letzte Änderung: Freitag, 5. August 2016, 18:58 von Manuela »

fugenkomponist

  • Gast
Re: Artikulationszeichen selbst entwerfen - wie?
« Antwort #3 am: Freitag, 5. August 2016, 19:03 »
Meine KLin malt das Zeichen immer in meine Noten, wenn ich eine Note betone, die nicht betont gehört.
Achso. Ja gut, ist ja auch irgendwie etwas universeller, wir haben das im Deutschunterricht für unbetonte Silben verwendet ;) Aber mir fiel halt als erstes Schönberg ein, der das in seinen Kompositionen verwendet.

Edit: Was mir grad noch eingefallen ist: Selbst wenn man ein Unicode-Zeichen (z. B. U+02D8) verwenden wollte, geht das nicht so wie ich dachte. Der folgende Code liefert „programming error: Cannot get a text stencil from this font“. Komischerweise gehts mit NoteHead, aber eben nicht mit Script. Und es hat nichts mit dem besonderen Zeichen zu tun, ein einfaches "a" tuts auch nicht …
\version "2.19.37"

soft =
-\tweak stencil #ly:text-interface::print
-\tweak text \markup \char ##x02D8
\fermata

{ c''\soft c''_\soft c''^\soft }
« Letzte Änderung: Freitag, 5. August 2016, 19:06 von fugenkomponist »

Manuela

  • Gast
Re: Artikulationszeichen selbst entwerfen - wie?
« Antwort #4 am: Freitag, 5. August 2016, 23:35 »
Magst du deine Lösung nicht ins LSR stellen? Mir gefällt sie sehr gut, sie ist möglicherweise auch für andere interessant, die nicht in diesem Forum hier lesen (können).

harm6

  • Gast
Re: Artikulationszeichen selbst entwerfen - wie?
« Antwort #5 am: Samstag, 6. August 2016, 15:36 »
Hallo zusammen,

ich habe mich auch mal intensiver mit der Materie befasst, wenn auch nicht zum ersten mal. Es gibt da ein paar Fallstricke...

\version für alle Beispiele ist "2.19.45"

Idealerweise sollte ein neues Scriptzeichen einige Kriterien erfüllen:
a) Es sollte bei veränderter fontSize korrekt skaliert werden
b) Es sollte ein anders Erscheinungsbild liefern, je nachdem ob es unter oder über dem Staff steht (falls nicht onehin symmetrisch)
c) Es sollte auch für \drummode geeignet sein, falls man eine neuen drumStyleTable anlegen möchte.

Zu den Lösungsansätzen:

1. \tweak bzw \override

Diese Methode überschreibt ein bereits existierendes Zeichen.
Falls im Code enthalten ist eine Anpassung an fontSize und 'direction möglich.

Nachteile:
- Es ist natürlich nicht wirklich ein neues Zeichen
- Es ist unmöglich dieses überschriebene Zeichen in eine neue drumStyleTable zu integrieren.

2. Neuer eintrag in default-script-alist aus script.scm

Falls erfolgreich so ist das neue Scriptzeichen universel anwendbar.

Problem:
1) Script hat ein 'script-stencil property, welches einen "Verweis" auf feta enthält, sowie ein pair von strings (die aus der feta-font ausgelesen werden) zur Auswahl des glyphs für über/unter dem Staff. Elaubt sind allerdings nur script-glyphs. Natürlich werden die glyphs dann mit der passenden font-metric genommen. Eigentlich ganz nett.
Aber dies macht es unmöglich dort custom-stencils abzulegen. Es gibt auch einen check, der nur strings dort akzeptiert, ansonsten gibts einen assertion error.
2) Falls 'script-stencil ungesetzt bleibt wird auf den 'stencil zurückgefallen.
Mit dem Nachteil das man dann keine richtungsabhängige stencil definieren kann. `default-script-alist' ist erstmal nur eine Liste, von einem grob oder dessen 'direction ist hier noch nicht die Rede und man kann von dort aus auch nicht auf das grob zugreifen. Auch das skalieren des stencils ist dort nicht möglich, da man wiederum keinen Zugriff auf die aktuelle fontSize erlangen kann.

Ad 1.

Hier habe ich mal den code von fugenkomponist aufgehübscht.

#(define new-stil
(lambda (grob)
  (let* ((sz (ly:grob-property grob 'font-size 0.0))
         (mult (magstep sz))
         (dir (ly:grob-property grob 'direction))
         (thick 0.15)
         (radius 0.7)
         (scaled-radius (* mult radius))
         (ps-command-string
           (format #f
             "
             0 ~a translate
             ~a setlinewidth
             ~a 0 moveto
             0 0 ~a 180 0 ~a
             stroke
             "
             ;mult
             (* thick dir)
             thick
             (- scaled-radius)
             scaled-radius
             (if (negative? dir) "arcn" "arc"))))
         
    (ly:make-stencil
      (list 'embedded-ps
            (format #f
              "
              gsave currentpoint translate
              ~a
              grestore
              "
             ps-command-string))
      (cons (- scaled-radius) scaled-radius)
      (cons
        (if (negative? dir) 0 (- scaled-radius))
        (if (negative? dir) scaled-radius 0))))))

soft =
-\tweak stencil #new-stil
%% maybe add:
%-\tweak staff-padding #'()
\fermata

m = { c''\soft c''_\soft c''^\soft c''-> }

<<
  \new Staff \with { fontSize = -6 } \m
  \new Staff \with { fontSize = 0 } \m
  \new Staff \with { fontSize = 6 } \m
>>

\drums {
  %% override takes no effect,because there _is_ no Script-grob!
  \override Script.stencil = #new-stil
  bd8 bd  bd2. hh1 hh2 hh4 hh8 hh cb
}

Mittels unicode wäre es:

softII =
-\tweak stencil #ly:text-interface::print
-\tweak staff-padding #'()
-\tweak text \markup \fontsize #2 \normal-text { \char ##x02D8 }
\fermata

{ c''\softII c''_\softII d''^\softII }

Man muß die font (feta-encoding für Scripts ist fetaMusic) zurücksetzen. Geht mit \normal-text.

Aber die oben beschrieben Nachteile bleiben bestehen.

Ad 2.

Hier habe ich einige stencil definiert, Setzungen für diese angegeben, mittels eines geeigneten macros in eine Kopie von `default-script-alist' eingefügt und diese dann im Score-layout angewendet.
Da die neuen script-stencils, die nicht auf feta-glyphs beruhen, nicht richtungsabhängig gemacht werden können, mußte ich an einer Stelle `arc' und `uarc' definieren.
Das Skalieren funktioniert wie schon gesagt auch nicht, insoweit kommt noch die Hilfsfunktion `scaleCustomScripts' zur Anwendung.

%% Working on a copy of `default-script-alist´ should warrant no bleed-over.
#(define my-script-alist (list-copy default-script-alist))

%% Some custom stencils
   
#(define ellipse-stil
  (ly:stencil-in-color
    (make-partial-ellipse-stencil 1 0.3 2 2 0.13 #t #f)
    1 0 0))
   
%% Code taken from
%% https://archiv.lilypondforum.de/index.php?topic=1279.msg7040#msg7040
%% by Torsten and modified
#(define (n-agon-stil nmbr)
  (let* ((th 0.1)
         ;; Value @code{6} returns a hexagon.
         (alpha-step (/ (* 2 PI) nmbr))
         (alpha-start (/ alpha-step 2))
         (radius 0.7)
         (polypoints
           (let loop ((alpha alpha-start))
             (if (> alpha (* 2 PI))
                 '()
                 (cons (* (abs radius) (sin alpha))
                       (cons (- 0 (* (abs radius) (cos alpha)))
                             (loop (+ alpha alpha-step))))))))
  (ly:make-stencil
    `(polygon ',polypoints  ,th #f)
    (cons (- radius) radius)
    (cons (- radius) radius))))


#(define (bezier-arc-stil direction)
  (make-connected-path-stencil
    `((0.15 ,direction  1.05 ,direction  1.2 0)) 0.2 1 1 #f #f))
 
%% Alists with the name of the new articulation and its settings.
#(define varsegno-settings
  `("varsegno"   
    . (
       (script-stencil . (feta . ("varsegno" . "varsegno")))
       (padding . 0.20)
       (avoid-slur . outside)
       (direction . ,UP))))
       
#(define ellipse-settings
  `("ellipse"   
    . (
       (avoid-slur . around)
       (padding . 0.20)
       (side-relative-direction . ,DOWN)
       (stencil . ,ellipse-stil))))
     
#(define hexagon-settings
  `("hexagon"   
    . (
       (avoid-slur . around)
       (padding . 0.20)
       (stencil . ,(n-agon-stil 6))
       (side-relative-direction . ,DOWN))))
     
#(define arc-settings
  `("arc"   
    . (
       (avoid-slur . around)
       (padding . 0.20)
       (stencil . ,(bezier-arc-stil -1))
       (side-relative-direction . ,DOWN))))
       
#(define up-arc-settings
  `("uarc"   
    . (
       (avoid-slur . around)
       (padding . 0.20)
       (stencil . ,(bezier-arc-stil 1))
       (side-relative-direction . ,DOWN))))
     
%% A macro used to put the lists from above in `my-script-alist´
#(define-macro (set-my-script-alist! ls-1 ls-2)
"Creates a new key-value-pair, taken from ls-2, in ls-1"
 `(set! ,ls-1
    (if (and (pair? ,ls-2) (pair? (cadr ,ls-2)))
        (assoc-set! ,ls-1 (car ,ls-2) (cdr ,ls-2))
        (begin
          (ly:warning (_"Unsuitable list\n\t~a \n\tdetected, ignoring. ") ,ls-2)
          ,ls-1))))

%% put the new articulations into `my-script-alist'
#(for-each
  (lambda (l)
     (set-my-script-alist! my-script-alist l))
  (list
    varsegno-settings
    ellipse-settings
    hexagon-settings
    arc-settings
    up-arc-settings))
   
%% `script-stencil' used for script-settings in script.scm looks for glyphs in
%% a font (feta), only explicit script-glyphs are accepted. The glyphs found are
%% scaled(?) to fit the current `fontSize'.  This seems to make it impossible to
%% put in there custom-stencils created by a procedure.  There are checks to
%% ensure strings to be in there. Also, if script-stencil is empty one should
%% fall back to stencil, which makes it impossible to get stencils with
%% different appearance for UP/DOWN, instead one has to define different
%% stencils for this purpose.
%% Anyway, here a workaround to get at least the scaling better.
scaleCustomScripts =
\override Script.before-line-breaking =
  #(lambda (grob)
    (let* ((script-stencil (ly:grob-property grob 'script-stencil)))
      (if (null? script-stencil)
          (let* ((sz (ly:grob-property grob 'font-size 0.0))
                 (mult (magstep sz)))
            (ly:grob-set-property! grob 'stencil
               (ly:stencil-scale
                 (ly:grob-property grob 'stencil)
                 mult
                 mult))))))
                 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Examples
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\header {
  title = "New Scripts"
  subtitle = "for"
  subsubtitle = "\\drummode and \\notemode"
  meter =
    \markup \fill-line {
      "defined are ellipse, hexagon, varsegno, arc and uarc"
    }
}

%% To use the new scripts call `my-script-alist' in \layout
%% Scale them accordingly
\layout {
  \context {
    \Score
    scriptDefinitions = #my-script-alist
    \scaleCustomScripts
  }
}

%%%%
%%%% default \notemode
%%%%

ellipse = #(make-articulation "ellipse")
hexagon = #(make-articulation "hexagon")
arc = #(make-articulation "arc")
uarc = #(make-articulation "uarc")
varsegno = #(make-articulation "varsegno")

%% Shortcuts.
%% TODO: How to create more shortcuts?
%% Below are redefined ones.
dashDash = "ellipse"
dashHat = "hexagon"

mus =
\relative c' {
c1-\ellipse d^\ellipse
e-\hexagon f^\hexagon
c'1-- d_-
e-^ f_^
c-\arc
c_\arc
c^\arc
c-\uarc
c_\uarc
c^\uarc
c_\varsegno
}

<<
  \new Staff \with { fontSize = -6 } \mus
  \new Staff \with { fontSize = 0 } \mus
  \new Staff \with { fontSize = 6 } \mus
>>

%%%%
%%%% \drummode
%%%%

%% A new drum-table
#(define mydrums
  '((bassdrum laThin "ellipse" -1)
    (hihat laThin  "hexagon"      3)
    (closedhihat cross "stopped" 3)
    (cowbell triangle "arc" 5)))

\layout {
  \context {
    \DrumStaff
      \override StaffSymbol #'line-count = #2
      drumStyleTable = #(alist->hash-table mydrums)
  }
}

drum-mus = \drummode { bd8 bd  bd2. hh1 hh2 hh4 hh8 hh cb }

<<
  \new DrumStaff  \with { fontSize = #-6 } \drum-mus
  \new DrumStaff  \with { fontSize = #0 } \drum-mus
  \new DrumStaff  \with { fontSize = #6 } \drum-mus
>>


Das ist natürlich ziemlich aufwendig, fumktioniert jetzt aber sowohl mit \notemode als auch mit \drummode.


Ich überlege eine feature-request zu schreiben, damit das Ganze etwas besser und angenehmer wird. Da ist aber auch in C++ zu kodieren. Insoweit kann ich es nicht selber machen, C++ kann ich nicht...

Komplettes file und png auch im Anhang.

HTH,
  Harm

Manuela

  • Gast
Re: Artikulationszeichen selbst entwerfen - wie?
« Antwort #6 am: Samstag, 6. August 2016, 19:15 »
Hallo Harm,

danke für die viele Mühe, die du dir machst (wieder einmal  :) )

Für meine Zwecke genügt der "einfache" Code, der im Drum Staff nicht funktioniert, da ich nur Piano Staff setze.

Wäre natürlich schön, wenn es in Lily einfachere Möglichkeiten gäbe, eigene Artikulationszeichen zu definieren.

Manuela

  • Gast
Re: Artikulationszeichen selbst entwerfen - wie? (gelöst)
« Antwort #7 am: Freitag, 12. August 2016, 14:39 »
Huch, ich bin schon zum Senior Member aufgestiegen  ;D

Fugenkomponist, vll. hast du meinen Vorschlag übersehen. Ich würde deinen Code gerne ins LSR-stellen, bist du damit einverstanden oder möchtest du das selber machen? Oder würde es dich stören, den Code im LSR wieder zu finden?

Hier nochmals der Code

\version "2.19.37"

soft =
-\tweak stencil
#(lambda (grob)
   (grob-interpret-markup grob
     #{
       \markup
       \with-dimensions #'(-0.7 . 0.7) #'(-0.7 . 0)
       \postscript
       #"0.15 setlinewidth -0.7 0 moveto 0 0 0.7 180 0 arc stroke"
     #}))
\fermata

{ c''-\soft }

harm6

  • Gast
Re: Artikulationszeichen selbst entwerfen - wie? (gelöst)
« Antwort #8 am: Samstag, 13. August 2016, 10:04 »
Zitat von: Manuela
Fugenkomponist, vll. hast du meinen Vorschlag übersehen. Ich würde deinen Code gerne ins LSR-stellen,
[...]
Hier nochmals der Code
[...]

Öhm, warum willst Du diesen Code ins LST packen?
Sicher, fugenkomponists code funktioniert erstmal. aber es gibt einige Beschänkungen:
Er skaliert nicht mit fontSize-Veränderungen. Und er dreht sich nicht mit veränderter 'direction.

Ich hatte hier (erstes Coding) eine Version eingestellt, die das alles automatisch erledigt.
Eigentlich der normale Weg: ein guter Ansatz wird weiterentwickelt. Warum den ersten Ansatz nehmen, wenn eine Weiterentwicklung existiert?

Ansonsten gibt es ja noch mein Coding unter dem selben link welches auch im drummode funktioniert. M.E. das Maximum an Funktionalität was auf scheme-Ebene (momentan) erreichbar ist.

Gruß,
  Harm

fugenkomponist

  • Gast
Re: Artikulationszeichen selbst entwerfen - wie? (gelöst)
« Antwort #9 am: Samstag, 13. August 2016, 10:33 »
Ich stimme harm hier zu, lieber gleich die Lösung, die mehr kann bzw. weniger Einschränkungen hat. Natürlich ist das auch mehr Code, aber für sowas gibts ja \include ;)