lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Automatically identify beats


From: Thomas Morley
Subject: Re: Automatically identify beats
Date: Sun, 7 Oct 2018 13:29:40 +0200

Am So., 7. Okt. 2018 um 07:31 Uhr schrieb Aaron Hill <address@hidden>:
>
> On 2018-10-06 10:01 am, Daniel Sales wrote:
> > Hi, is it possible to identify the beats on each different timing
> > automatically, in order to set a different color for strong, medium
> > and weak beats ?

> The biggest hurdle as I see it is computationally determining what is
> meant by "strong", "medium", and "weak".  Those labels might have an
> intuitive understanding by musicians, but for computers they require
> additional input.
>
> For instance, 6/8 timing could be thought of as "1 2 3 / 4 5 6" or "1 2
> / 3 4 / 5 6".

I disagree.
"1 2 / 3 4 / 5 6" feels like 3/4. No matter what is actual printed.

Even with Daniels manual coloring I disagree, more, the (not
demonstrated) 5/8 can be done as 2-3 or 3-2, etc

So I think one _must_ specify which colors are to be used and where.

Aaron's approach does so:

> So, let me propose an alternative to your original interface that will
> hopefully be both useful and easier to implement/maintain:
>
> %%%%
> \version "2.19.82"
>
> #(define (rational-color-pair? x)
>    (and (pair? x) (rational? (car x)) (color? (cdr x))))
> #(define (rational-color-pair-list? x)
>    (and (list? x) (rational-color-pair? (car x))
>      (or (null? (cdr x)) (rational-color-pair-list? (cdr x)))))
> colorizeBeats = #(define-music-function (args)
>    (rational-color-pair-list?)
>    "Conditionally overrides the color of the note head based on
>     its position within a measure."
>    #{ \override NoteHead.color = #(lambda (grob)
>         (let* ((moment (grob::rhythmic-location grob))
>                (matches? (lambda (m r)
>                  (eqv? 0 (ly:moment-main-numerator
>                    (ly:moment-mod m (ly:make-moment r))))))
>                (color (assoc (cdr moment) args matches?)))
>          (if color (cdr color)))) #} )
>
> {
>    \colorizeBeats #(list (cons 1/2 (x11-color 'red))
>                          (cons 3/8 (x11-color 'orange)))
>    \time 4/4 \repeat unfold 16 { b'8 }
>    \colorizeBeats #(list (cons 3/8 (x11-color 'red))
>                          (cons 3/16 (x11-color 'orange)))
>    \time 6/8 \repeat unfold 2 { b'8 8 8 8. 8. }
>    \colorizeBeats #(list (cons 1/4 (x11-color 'red))
>                          (cons 1/12 (x11-color 'orange)))
>    \time 5/4 \repeat unfold 2 { b'2 \tuplet 3/2 { 8 8 8 } 4 8 8 }
> }
> %%%%
>
> This approach does not attempt to parse the time signature but rather
> requires the user to provide a list of time intervals and their desired
> color.  Note that the first rule in the list that matches will be
> applied, so the ordering within the list is important.
>
> In the example provided, the first section highlights in red every half
> note (or more precisely, every note that *aligns* to a half note) and in
> orange every dotted quarter.  The second highlights dotted quarters and
> dotted eighths in a similar manner.  The third example shows the effect
> working with tuplets by coloring so-called "twelfth" notes.
>
> -- Aaron Hill_______________________________________________

Though, I think it clutters the input. (And returns inconsistent
results for \partial, although this would be not too had to fix.)

Below my own attempt using an engraver (to have access to the
'timeSignatureFraction, a context-property, and to Stem/NoteHead-grobs
in one go).
The colors are stored/mapped in a predefined list. The newly defined
context-property 'colorLikeTiming is set to this list. Making it
user-adjustable where needed.

Ofcourse there's wide room for improvements.
One example: _Every_ TimeSignature will have a strong emphasis at
first beat. Thus one could reflect this in the coding, currently
you'll have to explicitely set colors on every beat you want.
Or a better user-interface to adjust 'colorLikeTiming where needed.
But I'm lazy today ... ;)

\version "2.19.82"

#(define (define-translator-property symbol type? description)
  (if (not (and (symbol? symbol)
                (procedure? type?)
                (string? description)))
      (ly:error "error in call of define-translator-property"))
  (if (not (equal? (object-property symbol 'translation-doc) #f))
      (ly:error (_ "symbol ~S redefined") symbol))

  (set-object-property! symbol 'translation-type? type?)
  (set-object-property! symbol 'translation-doc description)
  symbol)

#(for-each
  (lambda (x)
    (apply define-translator-property x))
    `((colorLikeTiming
       ,list?
       "An alist which maps color-symbols to bar-position-fractions, relying
on time-signature-fractions.")))

#(define my-color-like-timing-list
  '(
    ;; 4/4
    ((4 . 4)
     .
     ((0 . red)
      (1/2 . green)))
    ;; 3/4
    ((3 . 4)
     .
     ((0 . red)
      (1/8 . orange)
      (1/4 . cyan)
      (3/8 . orange)
      (2/4 . cyan)
      (5/8 . orange)))
    ;; 2/2
    ((2 . 2)
     .
     ((0 . red)))
    ;; 8/8
    ((8 . 8)
     .
     ((0 . red)
      (1/8 . orange)
      (3/8 . orange)
      (1/2 . green)
      (5/8 . orange)
      (7/8 . orange)))
    ;; 6/8
    ((6 . 8)
     .
     ((0 . red)
      (3/8 . green)))
    ;; 5/8
    ((5 . 8)
     .
     ((0 . red)
      (3/8 . green)))
      ))

#(define (color-according-to-time-sig time-sig timing-color-ctx-prop)
  (lambda (grob)
    (ly:grob-set-property! grob 'color
      (lambda (grob)
        (let* ((loc (grob::rhythmic-location grob))
               (raw-in-bar-position (ly:moment-main (cdr loc)))
               ;; Care about negative position in \partial
               (in-bar-position
                 (if (negative? raw-in-bar-position)
                     (- (/ (car time-sig) (cdr time-sig))
                        (abs raw-in-bar-position))
                     raw-in-bar-position))
               ;; get the positions/colors from the predefined alist,
               ;; according to the relevant TimeSignature
               (timing-colors
                 (assoc-get time-sig timing-color-ctx-prop '()))
               ;; get the relevant color from timing-colors, according
               ;; to current position in bar
               (clr
                 (assoc-get in-bar-position timing-colors)))
          ;; Throw a warning, if no colors defined for this TimeSignature.
          ;; TODO Needed? Probably delete/comment
          (if (null? timing-colors)
              (ly:warning "No colors set for \\time ~a/~a"
                          (car time-sig) (cdr time-sig)))
          (if clr
              (x11-color clr)
              '()))))))

Color_like_time_signature_engraver =
#(lambda (context)
  (let ((time-sig-frac #f))
    (make-engraver
      (listeners
        ((rhythmic-event engraver event)
         ;; TODO
         ;; Will it always be sufficient to get 'timeSignatureFraction here?
         (set! time-sig-frac
               (ly:context-property context 'timeSignatureFraction))))
      (acknowledgers
        ((stem-interface engraver grob source-engraver)
         (let ((current-time-sig time-sig-frac)
               (time-sig-colors
                 (ly:context-property context 'colorLikeTiming)))
           ;; Stem shouldn't be printed on top of Beam
           (ly:grob-set-property! grob 'layer -100)
           ((color-according-to-time-sig current-time-sig time-sig-colors)
             grob)))
        ((note-head-interface engraver grob source-engraver)
         (let ((current-time-sig time-sig-frac)
               (time-sig-colors
                 (ly:context-property context 'colorLikeTiming)))
           ((color-according-to-time-sig current-time-sig time-sig-colors)
             grob))))
      ((finalize engraver)
       ;; Need to clear time-sig-fracs?
       ;; Better be paranoid
       (set! time-sig-frac #f)))))


\score {
  {
    \time 8/8
    \partial 8*7
    c'8[ 8 8] 8[ 8 8 8]
    c'1
    \repeat unfold 4 cis'4
    %\displayMusic
    \time 6/8
    d'4. 4.
    e'8 8 8 f'8 8 8
    \time 5/8
    g'8 8 8 8 8

    \time 2,3 5/8
    %% This 5/8 has different settings, so adjust 'colorLikeTiming
    \set Staff.colorLikeTiming =
      #'(((5 . 8)
         .
         ((0 . red)
          (2/8 . green))))

    g'8 8 8 8 8

    %% return to previous 'colorLikeTiming
    \set Staff.colorLikeTiming = \my-color-like-timing-list
    \time 5/8
    a'8 8 8 8 8

    \set beamExceptions = #'()
    \time  3/4
    b'8 8 8 8 8 8
    c''8 2 8

    \time 3/16
    d''16 16 16
  }
  \layout {
    \context {
      \Staff
      %% set the context-property 'colorLikeTiming
      colorLikeTiming = \my-color-like-timing-list
      %% consist the engraver in Staff
      \consists #Color_like_time_signature_engraver
    }
  }
}


HTH,
  Harm



reply via email to

[Prev in Thread] Current Thread [Next in Thread]