horizontalen Notenabstand dynamisch verändern

Begonnen von Notenkritzler, Sonntag, 4. November 2018, 15:43

« vorheriges - nächstes »

Notenkritzler

Hallo,

bisher haben mir die online verfügbaren Referenzen immer genügt - jetzt ein Problem, was ich damit scheinbar nicht gelöst bekomme:

Ist es möglich, mit Lilypond in einem 5-Linien-System (kein Gregorianik-System mit 4 Linien) trotzdem eine Form "Pseudo-Gregorianik" zu schreiben, daß z.B. die jeweils zweiten Noten der Phrasen (nur zur Illustration der Zusammengehörigkeit eingefügt) im Beispiel soweit nach links verschoben werden, daß sie über die erste gesetzt werden?

Akkorde wären evtl. eine Krücke, da aber ggf. auch MIDI erzeugt werden kann, scheinen sie nicht das Mittel der Wahl. Gibt es irgendwelche Hooks oder dgl. im Guile-Code, wo man so etwas erreichen kann?

Für alle zielführenden Hinweise dankbar - viele Grüße
der Notenkritzler


\include "deutsch.ly"
\version "2.19.80"

music = \relative c'' { g4( h) h( d) }

\score {
  \new Staff \music
  \layout {
    \context {
      \Staff \remove "Time_signature_engraver" \remove "Bar_engraver" \hide Stem
    }
    \context { \Voice \override Stem.length = #0 }
    \context { \Score barAlways = ##t }
  }
}

harm6


Notenkritzler

Hallo Harm,

vielen Dank für die Antwort. Die Seite hatte ich bereits gefunden und das, was man in den Beispielen sieht, durchprobiert. Ich kann auf diese Art zwar Noten(körper) näher zusammenrücken, aber nicht übereinanderstellen, was ich (bzw. tatsächlich ein guter Freund) wollte.

Da das Problem bisher nie aufgetaucht ist, hoffe ich, daß die Frequenz nicht sprunghaft steigt - mir wäre also auch ein aufwendigerer Weg, diese Darstellung (entspr. dem Podatus/Pes in der Quadratnotation, i.w.S. vielleicht auch Torculus, Porrectus?) zu erreichen, sehr willkommen.

harm6

Schau mal wie Du mit folgendem klar kommst. Die Ligaturzeichen \[ und \] werden umdefiniert und müssen in praefix-Syntax benutzt werden. Falls Du diese Zeichen doch brauchst benenne es anders.
Ich bin jetzt noch nicht weiter gegangen, da ich erst mal schauen wollte, ob es das ist was Du möchtest...
Kann auch sein, daß das ewige \newSpacingSection ungewollte Folgen nach sich zieht, mußt Du halt ausprobieren.


\version "2.19.82"

"\\[" = {
  \newSpacingSection
  \override Score.SpacingSpanner.packed-spacing = ##t
}

"\\]" = {
  \revert Score.SpacingSpanner.packed-spacing
  \newSpacingSection
  %% TODO compute the value
  \once \override NoteColumn.X-offset = -1.8
}

music =
\relative c'' {
\[g4\] b
\[b\] d
}

\score {
  \new Staff \music
  \layout {
    \context {
      \Staff
      \remove "Time_signature_engraver"
      \remove "Bar_engraver"
      \omit Stem
    }
    \context {
    \Score
    barAlways = ##t
    }
  }
}


Gruß,
  Harm

Notenkritzler

Hallo Harm,

vielen Dank, auch im Namen dessen, der das nutzen will - genau so etwas hatte ich gesucht und wollte das lernen.

Wo in der Dokumentation kann ich 'was dazu lesen, oder kennst du die Quellen so genau? Du hast den Kommentar hinterlassen, daß man den Abstand ggf. berechnen sollte - wo kann ich 'rauskriegen, wie man da am besten vorgeht?

Viele Grüße && nochmals Danke!
Der Notenkritzler (Eckard)

harm6

ZitatWo in der Dokumentation kann ich 'was dazu lesen, oder kennst du die Quellen so genau?
Zu newSpacingSection gibts ein eigenes Kapitel in der NR. Die anderen verwendeten properties packed-spacing und X-offset erklären sich eigentlich aus ihren Namen, ein bißchen Dokumentation ist aber auch in der NR bzw IR. Das man Eingabezeichen wie \[ neu setzen kann ist auch irgendwo gezeigt, das wäre hier aber auch anders machbar gewesen.
Ich kombiniere das Ganze allerdings auf ungewöhnliche Weise, da hilft eine tiefe Einsicht in die Quellen, sowie ihrer Eigenschaften natürlich.
Manches probiere ich auch einfach aus: eigentlich sollte es unmöglich sein zwei NoteColumn mittels X-offset übereinander zu schieben. Falls man newSpacingSection und packed-spacing verwendet gehts aber doch. Ich bin jedoch nicht sicher, ob ich hier nicht bug-using betreibe, .... pssst ;)

ZitatDu hast den Kommentar hinterlassen, daß man den Abstand ggf. berechnen sollte
Vielleicht hast Du bereits bemerkt, daß das Ganze bei verändertem layout (ragged-right = ##t reicht schon) aus der Kurve fliegt.  Der bisherige Code war wirklich nur ein proof-of-concept bzw eine demo um zu fragen, ob der putput in Deinem Sinne ist.
Um das robust hinzukriegen ist das TODO kein "wäre-schön" sondern eine Notwendigkeit.
Grob gesagt, muß man die Abstände der beiden NoteColumns berechnen und diesen Wert dem X-offset übergeben.

Leichter gesagt als getan natürlich, ich denk mal drüber nach (bin gleich offline und bei meinem regulären job) und schau ob ich heute abend was hinkriege.

Gruß,
  Harm

harm6

Hallo,

ich bin zum Code unten gekommen, welcher das gepostete Bild erzeugt.
Lese die Kommentare im Code dann sollte eigentlich klar werden wie es funktioniert.
Im wesentlichen wird die Funktion, die noch 'foo' heißt, auf den Inhalt von { ... } angewendet. Wobei das erste und letzte Element dort einen Slur starten bzw beenden müssen.
(Geht vielleicht auch anders, wär aber wohl mehr Aufwand.)
Optional kann ein weiterer Wert mitgegeben werden, der default ist #f dann werden die Ereignisse übereinander gelegt. Beim Wert 0 werden sie dicht (mit Abstand 0) gedruckt. Andere Werte können als Korrekturmöglichkeit verwendet werden.

Rein visuell ist das Ergebnis noch nicht befriedigend, da im Gegensatz zur Quadratnotation unsere heutigen schräg stehenden ellipsoiden Notenköpfe stärker zusammen gerückt werden könnten falls sie der Tonhöhe nach absteigen als wenn sie aufsteigen, da bin ich aber noch nicht dran gegangen.
Auch ist der output für Drei - und Viertonligaturen noch nicht wie in meiner Referenz. Dort ist es dann eine Art Kombination aus Pes und Einzelton oder zwei dichten gedruckten Pedes/Podati.
Brauchst Du das auch?

Aber hier der Code:


\version "2.19.82"

lig =
#(define-music-function (val music) ((boolean-or-number? #f) ly:music?)
  (let* ((lig-start
           #{
              \newSpacingSection
              \override Score.SpacingSpanner.packed-spacing = ##t
           #})
         (lig-stop
           #{
              \newSpacingSection
              \revert Score.SpacingSpanner.packed-spacing
           #})
         ;; insert start/stop of a ligature before slur-start/stop
         (new-music
           (if (music-is-of-type? music 'sequential-music)
               (make-sequential-music
                 (map
                   (lambda (mus)
                     (let* ((slur (extract-typed-music mus 'slur-event))
                            (span-dir (if (pair? slur)
                                          (ly:music-property
                                            (car slur)
                                            'span-direction)
                                          #f)))
                       (cond ((eqv? span-dir STOP)
                               (set! mus #{ $lig-start $mus #})
                               mus)
                             ((eqv? span-dir START)
                               (set! mus #{ $lig-stop $mus #})
                               mus)
                             (else mus))))
                   (ly:music-property music 'elements)))
                 music)))
    #{
      \override Slur.after-line-breaking =
        #(lambda (grob)
           (let* ((orig (ly:grob-original grob))
                  (siblings
                    (if (ly:grob? orig)
                        (ly:spanner-broken-into orig) '())))
             ;; Warn if Slur is broken and take no further action.
             (if (pair? siblings)
                 (ly:warning "Can't cope with broken events, ignoring")
                 ;; Otherwise catch the covered NoteColumns and move them
                 ;; towards the first NoteColumn:
                 ;; if 'val' is #f (the default) one above the other
                 ;; else move them towards the first NoteColumn as tight as
                 ;; possible, taking their extent into account.
                 ;; The "tightness" can be customized by setting 'val' to
                 ;; other numeric values than zero.
                 ;; This works best, if all NoteColumns have equal extents.
                 (let* ((ncs-array (ly:grob-object grob 'note-columns))
                        (ncs
                          (if (ly:grob-array? ncs-array)
                              (ly:grob-array->list ncs-array)
                              '()))
                        (ref-pt
                          (ly:grob-common-refpoint-of-array grob ncs-array X))
                        (ncs-x-coords
                          (map
                            (lambda (nc)
                              (ly:grob-relative-coordinate nc ref-pt X))
                            ncs))
                        (nc-x-lengths
                          (map
                            (lambda (nc)
                              (interval-length (ly:grob-extent nc ref-pt X)))
                            ncs)))
                   (for-each
                     (lambda (n nc d)
                       (let (
                             ;; Compute the needed value for the translating
                             ;; the NoteColumns
                             ;; Get them all above each other with:
                             ;;   Move them with (pseudocode)
                             ;;     their-x-coord - first-note-column-x-coord
                             ;;     in left direction, i.e.
                             ;;     (- (- d (car ncs-x-coords)))
                             ;; To get them tight:
                             ;;   introduce a value, which is calculated to
                             ;;   reflect the NoteColumn's x-length:
                             ;;     0 * first-x-length
                             ;;     1 * second-x-length
                             ;;     2 * third-x-length
                             ;;     ...
                             ;;   A little correction is possible
                             ;;   setting 'val' non-zero, leads to:
                             ;;     0 * first-x-length
                             ;;     (1 + val) * second-x-length
                             ;;     (2 + val) * third-x-length
                             ;;     ...
                             ;;   i.e.:
                             ;;   (- (- d n (car ncs-x-coords)))
                             ;;   where 'n' is the calculated correction value
                             
                             (tr-val (- (- d n (car ncs-x-coords)))))
                         (ly:grob-translate-axis! nc tr-val X)))
                     ;; calculate n
                     (if (not val)
                         ;; no correction if overlaying is wished
                         (make-list (length ncs) 0)
                         ;; else do as described above
                         (map
                           (lambda (ncl i) (* ncl i))
                           nc-x-lengths
                           (iota (length ncs) 0 (+ val 1))))
                     ncs
                     ncs-x-coords)))
            (ly:grob-set-property! grob 'stencil '())))
      $new-music
    #}))
       
\score {                 
  <<
    \new Staff {
      %\override TextScript.staff-padding = 2
      %\override TextScript.rotation = #'(20 0 0)
      \override TextScript.before-line-breaking =
        #(lambda (grob)
          (ly:grob-set-property! grob 'text
            (make-rotate-markup 15 (ly:grob-property grob 'text))))
      <>^"Pes"
      g'8[( b'])
      b'[( d''])
      <>^"Flexa"
      g'[( f'])
      <>^"Scandicus"
      <c'>[(  d'  e'])
      %\break
      <>^"Porrectus"
      a'[( f' a'])
      <>^"Torculus"
      g'[( a' g'])
      <>^"Climacus"
      a'[( g' f'])
      <>^"Salicus"
      f'[( a' b' d''])
    }
   
    \new Staff
      \new Voice
        \with {
          \omit Stem
          \omit Flag
          \omit Beam
        }
         
        {
          \lig { g'8( b') }
          \lig { b'( d'') }
          \lig #-0.25 { g'[( f']) }
          \lig #-0.1 { <c'>(  d'  e') }
          \lig #-0.3 { a'( f' a') }
          \lig #0 { g'( a' g') }
          \lig #0 { a'[( g' f']) }
          \lig #0 { f'( a' b' d'') }
        }
  >>
 
  \layout {
  indent = 0
  ragged-right = ##t
    \context {
      \Staff
      \remove "Time_signature_engraver"
      \omit BarLine
    }
    \context {
      \Score
      barAlways = ##t
    }
  }
}




Gruß,
  Harm

Notenkritzler

Hallo Harm,

das sieht alles super aus! Bin gestern und heute nicht mehr und heute (arbeitsbedingt) noch nicht zum Probieren gekommen, aber da steckt so viel drin, was mindestens Ansatzpunkte zum Selbst-Experimentieren gibt, wenn noch Sachen offen bleiben, würde ich gerne mal selbst probieren -- ist auch 'ne gute Gelegenheit, wieder mal Lisp (Scheme) in die Finger zu kriegen... :)

Also tausend Dank, ist wesentlich mehr, als ich erwartet hatte! Viele Grüße
Notenkritzler

harm6

Ich hab mir übrigens selbst das Leben schwerer gemacht als nötig: Da ich jetzt 'ly:grob-translate-axis!' anstelle von X-offset verwende ist die ganze Mühe \newSpacingSection und \override/revert SpacingSpanner in die Musik zu impfen völlig überflüssig.


lig =
#(define-music-function (val music) ((boolean-or-number? #f) ly:music?)
    #{
      \override Slur.after-line-breaking =
        #(lambda (grob)
           (let* ((orig (ly:grob-original grob))
                  (siblings
                    (if (ly:grob? orig)
                        (ly:spanner-broken-into orig) '())))
             ;; Warn if Slur is broken and take no further action.
             (if (pair? siblings)
                 (ly:warning "Can't cope with broken events, ignoring")
                 ;; Otherwise catch the covered NoteColumns and move them
                 ;; towards the first NoteColumn:
                 ;; if 'val' is #f (the default) one above the other
                 ;; else move them towards the first NoteColumn as tight as
                 ;; possible, taking their extent into account.
                 ;; The "tightness" can be customized by setting 'val' to
                 ;; other numeric values than zero.
                 ;; This works best, if all NoteColumns have equal extents.
                 (let* ((ncs-array (ly:grob-object grob 'note-columns))
                        (ncs
                          (if (ly:grob-array? ncs-array)
                              (ly:grob-array->list ncs-array)
                              '()))
                        (ref-pt
                          (ly:grob-common-refpoint-of-array grob ncs-array X))
                        (ncs-x-coords
                          (map
                            (lambda (nc)
                              (ly:grob-relative-coordinate nc ref-pt X))
                            ncs))
                        (nc-x-lengths
                          (map
                            (lambda (nc)
                              (interval-length (ly:grob-extent nc ref-pt X)))
                            ncs)))
                   (for-each
                     (lambda (n nc d)
                       (let (
                             ;; Compute the needed value for the translating
                             ;; the NoteColumns
                             ;; Get them all above each other with:
                             ;;   Move them with (pseudocode)
                             ;;     their-x-coord - first-note-column-x-coord
                             ;;     in left direction, i.e.
                             ;;     (- (- d (car ncs-x-coords)))
                             ;; To get them tight:
                             ;;   introduce a value, which is calculated to
                             ;;   reflect the NoteColumn's x-length:
                             ;;     0 * first-x-length
                             ;;     1 * second-x-length
                             ;;     2 * third-x-length
                             ;;     ...
                             ;;   A little correction is possible
                             ;;   setting 'val' non-zero, leads to:
                             ;;     0 * first-x-length
                             ;;     (1 + val) * second-x-length
                             ;;     (2 + val) * third-x-length
                             ;;     ...
                             ;;   i.e.:
                             ;;   (- (- d n (car ncs-x-coords)))
                             ;;   where 'n' is the calculated correction value
                             
                             (tr-val (- (- d n (car ncs-x-coords)))))
                         (ly:grob-translate-axis! nc tr-val X)))
                     ;; calculate n
                     (if (not val)
                         ;; no correction if overlaying is wished
                         (make-list (length ncs) 0)
                         ;; else do as described above
                         (map
                           (lambda (ncl i) (* ncl i))
                           nc-x-lengths
                           (iota (length ncs) 0 (+ val 1))))
                     ncs
                     ncs-x-coords)))
            (ly:grob-set-property! grob 'stencil '())))
      $music
    #})
       
\score {                 
  <<
    \new Staff {
      \override TextScript.before-line-breaking =
        #(lambda (grob)
          (ly:grob-set-property! grob 'text
            (make-rotate-markup 15 (ly:grob-property grob 'text))))
      <>^"Pes"
      g'8[( b'])
      b'[( d''])
      <>^"Flexa"
      g'[( f'])
      <>^"Scandicus"
      <c'>[(  d'  e'])
      %\break
      <>^"Porrectus"
      a'[( f' a'])
      <>^"Torculus"
      g'[( a' g'])
      <>^"Climacus"
      a'[( g' f'])
      <>^"Salicus"
      f'[( a' b' d''])
    }
   
    \new Staff
      \new Voice
        \with {
          \omit Stem
          \omit Flag
          \omit Beam
        }
         
        {
          \lig { g'8( b') }
          \lig { b'( d'') }
          \lig #-0.25 { g'[( f']) }
          \lig #-0.1 { <c'>(  d'  e') }
          \lig #-0.3 { a'( f' a') }
          \lig #0 { g'( a' g') }
          \lig #0 { a'[( g' f']) }
          \lig #0 { f'( a' b' d'') }
        }
  >>
 
  \layout {
  indent = 0
  ragged-right = ##t
    \context {
      \Staff
      \remove "Time_signature_engraver"
      \omit BarLine
    }
    \context {
      \Score
      barAlways = ##t
    }
  }
}



Dann bessert sich auch das allgemeine Spacing.


Gruß,
  Harm

harm6

#9
Dann kann man sich im Aufruf der Funktion auch die {} sparen, evtl. mit \once
Z.B.  \once \lig g'8( b')

Gruß,
  Harm

EDIT
Ich war zu eifrig.
Das mit \once geht so nicht.
Mögliche wäre das \once in die Funktion zu packen: \once \override Slur ...
Ansonsten denk ich mal drüber nach ... ;)