Hi,

Thank you all for your encouragements − it's a pleasure to know that your work is appreciated.

This prompted me to rewrite the thing …

Le 23/10/2020 à 21:30, Carl Sorensen a écrit :

This is a beautiful quick hack!

To avoid the semicircles on the the end of each staff line, you'd likely want to change the definition of the staffline being printed.  This is defined in the file lily/staff-symbol.cc as a horizontal line (see lines 92 and 93) of a given thickness, which is drawn with a pen having a blot diameter of the thickness.  It's probably possible to rewrite this print function in Scheme and draw the staff line as a round-filled-box (see lily/lookup.cc).  If I were trying to do this in the minimum effort way possible, I'd hardcode a blot diameter, and draw a round-filled box of the given thickness using the hardcoded blot diameter.  This would be a hack, but would get the job done.


… in a way that, as you say, redraws the StaffSymbol instead of creating a bunch of RhythmicStaff contexts, so you can pass plain music without resorting to complicated combinations of \crossStaff and \change (cross-staff chords are cumbersome to create). This is indeed done by partly reimplementing and partly reusing the callback found in lily/staff-symbol.cc. Fortunately, you don't need the ability to compile LilyPond; all of this is done via Scheme.

And, you were right: I used \filled-box to control the blot diameter, which is set to a fixed value (you can modify it as a global variable).

The problem so far is that I didn't find a proper way to set the chord configuration at a given musical moment (note heads placed at the left or at the right of the stem). For now I've used an extra-offset, which leads to inconsistent spacing. There is \override Stem.note-collision-threshold = 50, but that doesn't let you achieve the fourth chord before the end, where the upper note is on the left and the lower note is on the right, since the usual placement is the other way around.

Code attached, with an output that resembles the image you (Michael) sent earlier. Note that you need a development version of LilyPond (lilypond.org/development). Naturally, this is only a start since at this point more details are needed about the specification of what you want to achieve. Nevertheless, I wanted to share this code to avoid duplication of effort in case someone else were willing to take over this topic.

Regards,
Jean

\version "2.23.0"

% You can play around with these parameters.

line-count = 12
stem-end-position = 17
inter-line-gap = 2
min-grey = 0
max-grey = 0.7
min-thickness = 0.1
thickness-increment = 0.013
stem-thickness = 2
staff-line-blot = 0.2
light-blue = "CornflowerBlue"
note-head-base = \markup \filled-box #'(-0.6 . 0.6) #'(-0.5 . 0.5) #0.9

#(define-markup-command (whiteout-outline-with-color layout props thickness color arg)
                        (number? color? markup?)
   (stencil-whiteout-outline (interpret-markup layout props arg) thickness color))

note-head-part-one =
\markup
  % Strange that \whiteout-outline-with-color #0.1 #black \with-color #blue \note-head
  % doesn't work here. Let's work around.
  \combine
  \whiteout-outline-with-color
    #0.15
    #black
    \with-color #black \note-head-base
  \with-color #light-blue \note-head-base

note-head-part-two =
\markup
  \whiteout-outline-with-color
    #0.15
    #black
    \note-head-base
    
note-head-combined =
\markup \overlay {
    \note-head-part-one
    \translate #'(-0.5 . 0) \note-head-part-two
    \translate #'(-0.7 . -0.4) \rotate #-150 \fontsize #-9 \with-color #white \number "2"
}

#(define (calc-note-head-text grob)
   (if (ly:grob-property grob 'has-headphones)
       note-head-combined
       note-head-part-two))


% Not defined?
#(define pi (acos -1))

#(define (greyscale x)
   (let* ((value (+ (* (+ (/ (atan x) pi) 0.5) (- max-grey min-grey)) min-grey)))
     (rgb-color value value value)))

#(define (calc-thickness x)
   (+ min-thickness (* thickness-increment (abs x))))


#(define (calc-stem-position grob)
  (- stem-end-position (ly:grob-property grob 'stem-begin-position)))



% From lily/staff-symbol.cc
#(define (calc-staff-symbol-line-positions grob)
  (let* ((line-count (ly:grob-property grob 'line-count))
         (height (- line-count 1)))
    (map
      (lambda (i) (- height (* 2 i)))
      (iota line-count))))




#(define (calc-staff-symbol-stencil grob)
   (let ((x-extent (ly:stencil-extent (ly:staff-symbol::print grob) X)))
     (apply ly:stencil-add
       (map
         (lambda
          (x)
          (let ((thickness (calc-thickness x)))
            (ly:stencil-translate-axis
               (grob-interpret-markup grob
                #{
                  \markup
                    \with-color #(greyscale x)
                    \filled-box #x-extent #(cons (- thickness) thickness) #staff-line-blot
                #})
                (* (ly:grob-property grob 'staff-space 1) 0.5 x)
                Y)))
         (ly:grob-property grob 'line-positions)))))


% Borrowed from Pierre
% https://www.mail-archive.com/lilypond-user@gnu.org/msg140189.html
#(define (define-grob-property symbol type? description)
   "Define a new grob property.
`symbol': the property name
`type?': the type predicate for this property
`description': the type documentation"
  (set-object-property! symbol 'backend-type? type?)
  (set-object-property! symbol 'backend-doc description)
  symbol)


#(define-grob-property
  'has-headphones
  boolean?
  "Should this note be printed with headphones?")

\paper {
  page-breaking = #ly:one-line-auto-height-breaking
}

\layout {
  \context {
    \Score
    \remove System_start_delimiter_engraver
  }
  \context {
    \Staff
    \remove Bar_engraver
    \remove Clef_engraver
    \remove Time_signature_engraver
    \override Stem.thickness = #stem-thickness
    \override Stem.direction = #UP
    \override NoteHead.stencil = #ly:text-interface::print
    \override NoteHead.text = #calc-note-head-text
    \override Stem.length = #calc-stem-position
    \override Stem.X-offset = 0.63
    \override StaffSymbol.line-count = #line-count
    \override StaffSymbol.line-positions = #calc-staff-symbol-line-positions
    \override StaffSymbol.stencil = #calc-staff-symbol-stencil
    \override NoteHead.has-headphones = ##f
  }
}

headphones = \tweak has-headphones ##t \etc
move = \tweak NoteHead.extra-offset
  #(lambda (grob)
     (if (ly:grob-property grob 'has-headphones)
         '(1.78 . 0)
         '(1.30 . 0)))
  \etc

addSmallSpacing = {
  \once \override Score.SpacingSpanner.spacing-increment = 0.4
  s
  \newSpacingSection
}




\relative {
  \addSmallSpacing
  e'''
  <e \move \headphones f,>
  c
  <a \move c>
  a
  <a \move \headphones f>
  f
  \headphones f
  d
  <b \move c'>
  \headphones b
  b
  <b \move a,>
  <g \move a'>
  \headphones g
  g
  e
  e
  <c \move a>
  a
  <f \move \headphones f''>
  f
}

Attachment: Fancy2.pdf
Description: Adobe PDF document

Reply via email to