lilypond-user
[Top][All Lists]
Advanced

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

Re: Using circles in \tabFullNotation


From: Jean Abou Samra
Subject: Re: Using circles in \tabFullNotation
Date: Sun, 31 Jan 2021 00:42:22 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.5.0

Hi,

(Also forwarding to the list, please keep it in CC.)


Le 30/01/2021 à 16:57, Kuredant a écrit :
Thanks a lot! I wouldn't have been able to come up with that myself.

The code works very well, especially for chords.

I have two minor issues:

– The stem is right below the lowest fret number, but I'd like it in the middle of the circle.

– The overrides apply to all notes regardless of their lengths (e.g. quarter notes also have a circle around them). For this issue I think I can check the source code for \tabFullNotation.

This shouldn't be too complex so I'll try to figure it out for myself.

> Your hunch is correct. Try this somewhat experimental
> code (note that I am not sure how you are positioning the
> TabNoteHead grobs horizontally, I used an X-offset).

I didn't know how to change the horizontal position of a single TabNoteHead, thanks. My images come from a Japanese tab I scanned. I just wanted to mimic its style.


Here is a new version.

Beware that I am coding to my maximum capacity. In particular, I don't at all understand why LilyPond behaves the way it does in some parts of the code (see the comments).

As you say, the two issues were not all too complex (when you know the functions at hand). However, after quite some time messing up with pure and unpure calls, I have not found a proper solution to handle the extents. Thus, you will have to do a very bit of manual spacing when dots are present.

Maybe someone on this list can explain what is happening with X-offset (or maybe it will become obvious to me tomorrow).

Best,
Jean


\version "2.23.0"

% Define new grob properties used for Stem

#(set-object-property! 'oval-thickness 'backend-type? number?)
#(set-object-property! 'oval-x-padding 'backend-type? number?)
#(set-object-property! 'oval-y-padding 'backend-type? number?)
#(set-object-property! 'is-special 'backend-type? boolean?)


#(define (calc-stem-is-special stem)
   "Only stems for half and whole notes are made special."
   (let* ((cause (event-cause stem))
          (duration (ly:event-property cause 'duration)))
     (>= 1 (ly:duration-log duration))))


% Amended from scm/stencil.scm, to use #t for filling

#(define (filled-oval-stencil stencil thickness x-padding y-padding)
  (let* ((x-ext (ly:stencil-extent stencil X))
         (y-ext (ly:stencil-extent stencil Y))
         (x-length (+ (interval-length x-ext) x-padding thickness))
         (y-length (+ (interval-length y-ext) y-padding thickness))
         (x-radius (* 0.707 x-length) )
         (y-radius (* 0.707 y-length) )
         (oval (make-oval-stencil x-radius y-radius thickness #! #f !# #t)))
    (ly:stencil-add
     stencil
     (ly:stencil-translate oval
                           (cons
                            (interval-center x-ext)
                            (interval-center y-ext))))))

#(define (coords-for-axis stem note-head-array note-heads axis)
   "Compute relative coordinates of note heads relative to
    the stem along given axis."
   (let* ((refpoint (ly:grob-common-refpoint-of-array stem note-head-array axis))
          (note-head-coords (map (lambda (note-head)
                                   (ly:grob-relative-coordinate
                                     note-head
                                     refpoint
                                     axis))
                                 note-heads))
           (stem-coord (ly:grob-relative-coordinate
                         stem
                         refpoint
                         axis))
           (scaled-coords (map (lambda (coord)
                                 (- coord stem-coord))
                               note-head-coords)))
      scaled-coords))

#(define (custom-stem-stencil stem)
   "Draw a stem and an oval around all note heads found."
   (if
     (not (ly:grob-property stem 'is-special))
     (ly:stem::print stem)
     (let* ((stem-stencil (ly:stem::print stem))
            (oval-thickness (ly:grob-property stem 'oval-thickness))
            (oval-x-padding (ly:grob-property stem 'oval-x-padding))
            (oval-y-padding (ly:grob-property stem 'oval-y-padding))
            (note-head-array (ly:grob-object stem 'note-heads))
            (note-heads (ly:grob-array->list note-head-array))
            ; The note heads have their X-offset property set
            ; by the \tweaks. Why the hell is it always zero
            ; here?
            ;(nothing
            ;       (for-each (lambda (note-head)
            ;         (ly:message "~s" (ly:grob-property note-head 'X-offset)))
            ;         note-heads))
            (relative-x-coords (coords-for-axis stem note-head-array note-heads X))             (relative-y-coords (coords-for-axis stem note-head-array note-heads Y))
            (stencils (map tab-note-head::print note-heads))
            (coord-pairs (map cons relative-x-coords relative-y-coords))
            (translated-stencils (map ly:stencil-translate stencils coord-pairs))
            (combo-stencil (apply ly:stencil-add translated-stencils))
            (oval (oval-stencil combo-stencil oval-thickness oval-x-padding oval-y-padding))
            (filled-oval (filled-oval-stencil combo-stencil
                                              oval-thickness
                                              oval-x-padding
                                              oval-y-padding))
            (white-filled-oval (stencil-with-color filled-oval white))
            (final-stem-stencil
              (if (not (null? stem-stencil))
                (ly:stencil-translate-axis
                  stem-stencil
                  (- (interval-center (ly:stencil-extent oval X))
                     (interval-center (ly:stencil-extent stem-stencil X)))
                  X)
              empty-stencil)))

       (ly:stencil-add
         final-stem-stencil
         white-filled-oval
         oval))))

#(define (calc-stem-x-extent stem)
   ; Rely on the fact that when the stem is
   ; special, there is no beam!
   (if (ly:grob-property stem 'is-special)
       (ly:stencil-extent
          (ly:grob-property stem 'stencil)
          X)
       (ly:stem::width stem)))


#(set-object-property! 'extra-dot-padding 'backend-type? number?)
#(define (calc-tab-note-head-x-extent note-head)
   ; Absolutely horrible kludge. If the note
   ; head belongs to a circled stem and has a
   ; dot, add padding on its right. We should
   ; really take the extent of the stem's stencil
   ; but this seemingly introduces a cyclic
   ; dependency, most probably because the stem's
   ; stencil itself takes the coordinates of the
   ; note heads. That should be fixed to use X-offset
   ; only, but it doesn't work for some reason.
   (let ((extent (ly:stencil-extent
                   (ly:grob-property note-head 'stencil)
                   X)))
     (if (and
           (ly:grob-property
             (ly:grob-object note-head 'stem)
             'is-special)
           (not (null? (ly:grob-object note-head 'dot))))
         (set-cdr! extent (+ (ly:grob-property note-head 'extra-dot-padding)
                             (cdr extent))))
     extent))

\layout {
  \context {
    \TabVoice
    \override Stem.is-special = #calc-stem-is-special
    \override Stem.stencil = #custom-stem-stencil

    % You can set these.
    \override Stem.oval-thickness = 0.1
    \override Stem.oval-x-padding = 0.75
    \override Stem.oval-y-padding = 0.75

    \override TabNoteHead.extra-dot-padding = 1.0

    \override TabNoteHead.X-extent = #calc-tab-note-head-x-extent

    % The oval is drawn over the stem. Lower the layer to prevent
    % it from going over the staff symbol too.
    \override Stem.layer = -1

    % Override default extent calculations, because those do not
    % actually use the stencil.
    \override Stem.X-extent = #calc-stem-x-extent
    %%% Doesn't work, why?
    %%% \override Stem.Y-extent = #(ly:make-unpure-pure-container grob::always-Y-extent-from-stencil)
    \override Stem.Y-extent = #grob::always-Y-extent-from-stencil
  }
}


\new TabStaff {
  \tabFullNotation
  <a \tweak X-offset -1 c' \tweak X-offset 0.2 e'>1
  q2. q4
  % You may occasionally need this:
  \once \override TabNoteHead.extra-dot-padding = 1.25
  <a \tweak X-offset 2 c' e'>2. <a \tweak X-offset -1 c' \tweak X-offset 0.2 e'>4
  q8 8 8 8 16 16 16 16 16 16 16 16
}




reply via email to

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