Autor Thema: Spezielle Taktnummerierung  (Gelesen 2306 mal)

CzgMax

  • Gast
Spezielle Taktnummerierung
« am: Donnerstag, 6. März 2014, 20:06 »
Hallo zusammen,

auch wenn das mein erster Forumpost ist, ist diese Frage möglicherweise schon etwas spezieller. Daher zunächst eine kurze Erklärung:

Ich setze gelegentlich kürzere Stücke für eine kleine Gruppe (jeweils für ein Instrument bzw. Stimme pro Dokument). Dabei hat sich bei uns (aus Zeiten selbstgeschriebener handschriftlicher Noten) eine Taktnummerierung durchgesetzt, bei der die Taktzahl sowohl immer am Anfang der Zeile auftaucht, als auch an Stellen in der Mitte von langen Notenzeilen. Das ist insbesondere dann nützlich, wenn Notenzeilen aufgrund von Pausentakten länger werden. Es gibt bei Proben häufig Beschwerden, wenn Takte aufgrund fehlender Nummerierung nicht gefunden wurden.  ;)

Dieses Verhalten habe ich daher mit Lilypond nachzubilden versucht, bin jedoch mit der Lösung unzufrieden. Hier dazu ein kurzes Beispiel (bestehend aus drei Beispielen, deswegen eigentlich schon wieder etwas länger):

\version "2.18.0"

music = \relative c' { \repeat unfold 20 { | c2 e2 | r1 } }

%% ========================================================
%% First example: just every bar number visible
%% ========================================================
\score { \new Staff { \set Staff.instrumentName = \markup { "First" }
  \override Score.BarNumber #'break-visibility = #'#(#f #t #t) % No real filter
  \set Score.barNumberVisibility = #(every-nth-bar-number-visible 4) % Return #t every 4 bars
  \music
}}

%% ========================================================
%% Second example: only the first barnumber in every line is visible
%% ========================================================
\score { \new Staff { \set Staff.instrumentName = \markup { "Second" }
  \override Score.BarNumber #'break-visibility = #'#(#f #f #t) % Filter beginning of lines
  \set Score.barNumberVisibility = #all-bar-numbers-visible % Return always #t
  \music
}}

%% ========================================================
%% Third exmaple: certain bar numbers visible
%% ========================================================

% See here: http://blog.flowblok.id.au/2010-11/box-specific-bar-numbers-in-lilypond.html
certain-bar-numbers = #(lambda (barnumber measure-position)
                         (not
                           (eq? (member barnumber '(5 10 15 21 26 31 36)) #f)))

\score { \new Staff { \set Staff.instrumentName = \markup { "Third" }
  \override Score.BarNumber #'break-visibility = #'#(#f #t #t)
  \set Score.barNumberVisibility = #certain-bar-numbers
  \music
}}

Die ersten beiden Fälle sollten bekannt sein; sie dienen nur der Illustration des Problems. Dieses besteht in der Art und Weise, wie ermittelt wird, ob ein Takt nummeriert wird. Es gibt letztlich die Eigenschaften break-visibility und barNumberVisibility. Letztere (barNumberVisibility) wird zuerst ausgewertet und führt eine Funktion mit zwei Argumenten aus (Taktzahl und Position im Takt) und liefert ob der Takt eine Nummerierung erhält. Die erste Eigenschaft (break-visibility) filtert dann noch einmal, indem spezifiziert wird, wo in einer Notenzeile überhaupt Taktnummerierungen stehen dürfen. Will man beispielsweise nur die ersten Takte einer jeden Zeile nummerieren, so lässt man die Funktion hinter barNumberVisibility einfach immer #t zurück geben und filtert anschließend mit break-visibility die Zeilenanfänge heraus.

Soweit so gut, nun kann man diese Filterung von break-visibility im vorliegenden Fall nicht verwenden, soweit ich das verstehe, da ja prinzipiell am Anfang einer Zeile nummeriert werden sollte, jedoch unter gewissen Umständen auch an anderen Stellen. D.h. die Logik muss in der Funktion bei barNumberVisibility unterkommen. Auch das ist zunächst kein Problem, solange die Berechnung nur auf Basis der Taktzahl erfolgt (z.B. eben jeder 5. Takt). Ich möchte allerdings trotzdem jeden ersten Takt einer Zeile nummerieren. An dieser Stelle finde ich jedoch keine Möglichkeit mehr zu bestimmen, ob der aktuelle Takt der erste in einer Zeile ist.

tl;dr: Wie nummeriert man den ersten Takt jeder Zeile und zusätzlich weitere Takte (z.B. jeden fünften oder etwa in der Mitte der Zeile)?
Mein einziger Ansatz ist die Lösung "von Hand" (siehe drittes Beispiel), welche jedoch offensichtlich umständlich ist, und ein absolutes Grauen, wenn sich Zeilen aufgrund von kleinen Änderungen verschieben.

Mein Verständnis der Lilypond Architektur ist leider nicht ausreichend (und außer in Lilypond habe ich auch Scheme noch nie verwendet) um das Problem so zu lösen.   :( Helfen würde mir auch ein Hinweis, wie ich z.B. anhand der Zeilennummer ermitteln kann, wo in der Notenzeile sich ein Takt letztlich befindet o.Ä. Interessant ist möglicherweise folgender Thread:

http://web.archiveorange.com/archive/v/nRTVV7TW4Ey3ZQKSjQ44

Die Funktion  ly:item-break-dir wäre definitiv nützlich, allerdings wollte ich nicht zwangläufig die stencil Eigenschaft verändern (da meinem Verständnis nach das Objekt "Taktnummer" dann eigentlich schon da ist, und z.B. in Abstandsberechnungen einbezogen wird). Oder sehe ich das falsch?

Ich denke ja fast, dass ich einfach etwas übersehe und es eine viel einfachere Lösung dafür gibt... Vielen Dank schon einmal für jede Anregung,

Max

P.S.: Optimalerweise hätte vielleicht sogar jemand einen Vorschlag, wie man ermittelt ob sich ein Takt genau in der Mitte der Notenzeile befindet?  ;)

Arnold

  • Gast
Re: Spezielle Taktnummerierung
« Antwort #1 am: Freitag, 7. März 2014, 08:48 »
Hallo,

diese Großpausen-Takzählerei hat mich auch immer gestört.
Ich habe allerdings nicht noch regelmäßig Taktzahlen hinzugefügt, sondern nur nach Mehrtaktpausen ab 3 Takten Länge.

Ich hoffe mal, daß ich aus meiner privaten Include-Datei nur die Zeilen für die anderen Funktionen hier entfernt habe:
#(define (self-alignment-x-rcc grob) ;; 'rcc' = Right-Center-Center
   (let ((break-dir (ly:item-break-dir grob)))
     (case break-dir
       ((1)  RIGHT)     
       ((0)  CENTER)
       ((-1) CENTER)
       (else CENTER))))

#(define (volta-start-in-repeat-command rcl)
  (if (or (null? rcl)
          (not (pair? rcl))
          (not (pair? (car rcl))))
   #f
   (let ((cmd (caar rcl))
         (pos (cadar rcl)))
    (if (and (eq? cmd 'volta)
             (not (boolean? pos)))
     #t
     (volta-start-in-repeat-command (cdr rcl))
    )
   )
  )
 )

#(define (Barnumber_additional_visibility_engraver ctx)
  (let ((barnums-seen '())
        (barline-seen #f)
        (notehead-seen #f)
        (noteheads-found #f)
        (last-barnums '())
        (last-bar-barnumber #f)
        (show-barnumber-required #f)
        (show-by-volta-start #f)
       )

    `((acknowledgers
       (grob-interface
        . ,(lambda (trans grob source)
            (let ((grob-name (ly:assoc-get 'name (ly:grob-property grob 'meta))))
             (if (eq? grob-name 'NoteHead)  (set! notehead-seen #t))
             (if (eq? grob-name 'BarNumber) (set! barnums-seen (cons grob barnums-seen)))
             (if (eq? grob-name 'BarLine)   (set! barline-seen #t))
           ))
       )
      )
      (start-translation-timestep
       . ,(lambda (trans)
           (let ((current-barnum (ly:context-property ctx 'currentBarNumber)))
            (set! barnums-seen '())
            (set! barline-seen #f)
            (set! notehead-seen #f)
          ))
      )
      (stop-translation-timestep
       . ,(lambda (trans)
           (let
            ((current-barnum (ly:context-property ctx 'currentBarNumber))
             (measure-pos (ly:context-property ctx 'measurePosition))
             (rep-cmds (ly:context-property ctx 'repeatCommands))
             (volta-starts (volta-start-in-repeat-command (ly:context-property ctx 'repeatCommands)))
            )
            (if (volta-start-in-repeat-command (ly:context-property ctx 'repeatCommands))
             (set! show-by-volta-start #t))
            ; before the barline ...
            (if (and barline-seen
                     noteheads-found
                     (number? last-bar-barnumber)
                     (> (- current-barnum last-bar-barnumber) 1))
             (set! noteheads-found #f)
            )
            (if (and barline-seen
                     (not noteheads-found)
                     (number? last-bar-barnumber)
                     (>= (- current-barnum last-bar-barnumber) 3))
             (set! show-barnumber-required #t)
            )
             
            ; after the barline ...
            (if (and (not (null? barnums-seen))
                     show-barnumber-required
                     noteheads-found
                     (not (null? last-barnums))) (begin
              (for-each (lambda (g)
                (ly:grob-set-property! g 'break-visibility end-of-line-invisible)
                ; (ly:grob-set-property! g 'color red)
               ) last-barnums)
              (set! show-barnumber-required #f)
            ))

            (if (and (not (null? barnums-seen))
                     show-by-volta-start) (begin
              (for-each (lambda (g)
                (ly:grob-set-property! g 'break-visibility end-of-line-invisible)
                ; (ly:grob-set-property! g 'color magenta)
               ) barnums-seen)
              (set! show-barnumber-required #f)
              (set! show-by-volta-start #f)
            ))

            (if (not (null? barnums-seen)) (begin
              (set! last-barnums barnums-seen)
              (set! barnums-seen '())
            ))

            (if barline-seen (begin
              (set! last-bar-barnumber current-barnum)
              (set! noteheads-found #f)
              (if notehead-seen (set! noteheads-found #t))
            ))


            (if notehead-seen (set! noteheads-found #t))
           
          ))
      )
 )))

\layout {
  \context { \Score
    \consists #Barnumber_additional_visibility_engraver
    alternativeNumberingStyle = #'numbers-with-letters
    barNumberVisibility = #all-bar-numbers-visible
    \override BarNumber #'break-visibility = #begin-of-line-visible
    \override BarNumber #'self-alignment-X = #self-alignment-x-rcc
  }
}

showBarNumber = #(define-music-function (parser location) ()
#{
  \once \override Score.BarNumber #'break-visibility = #end-of-line-invisible
#})
Prinzipiell zeige ich erst einmal nur die Taktzahlen am Zeilenanfang an.
Außerdem setze ich für die Ausrichtung eine Callback-Funktion - am Zeilenanfang rechtsbündiger Text, sonst mittig.
Ein Engraver übernimmt dann die Taktzählerei-Auswertung, und ändert an den entsprechend bewerteten Taktzahlen die break-visibility-Maske auf #end-of-line-invisible.

Grundsätzlich gilt: Da der Engraver vor der Zeilenumbruch-Aktion läuft, kann er auch nicht "jede x-te Taktzahl nach einem Zeilenumbruch" sichtbar machen, er kann allenfalls vom Anfang des Satzes an stur durchzählen.

Ich hoffe, das hilft schon mal weiter,

Arnold