Re: Identifying Tonic in function & default lambda va

2019-12-18 Thread Michael Käppler

Hi Holleyanne,
please always try to provide a complete (minimal) example which is ready 
to try it out.

It is more likely then that somebody will respond to your question.

An adapted version of your snippet is attached.

First few remarks for providing optional arguments.
In a simple (lambda) statement, as you tried, this is not possible. A 
common approach

then is to provide an argument list and extract what you need.

Like:

colorNoteheads-c =
#(lambda (args)
  (let ((color-outline? (car args))
  (line-width (second args))
[...]

You can check the length of the argument list and see, if (or how many) 
optional

arguments are given.

Another possibility is to use the built-in (define-scheme-function), 
which also has

the possibility to do simple type checks.
See: 
http://lilypond.org/doc/v2.18/Documentation/extending/scheme-function-definitions.html


The problem with optional arguments is, that the last argument cannot be 
optional.
(Reasons are described in 
http://lilypond.org/doc/v2.18/Documentation/extending/scheme-function-usage.html)

Thus I changed the order of arguments:

coloredNoteheads-c =
#(define-scheme-function (tonic-pitch line-width tonic-color part-color 
color-outline?)

   (ly:pitch? number? color? (color? black) boolean?)

It is of course possible to pass a tonic pitch to this function as an 
argument.
Using context properties with this kind of callback function is not 
possible, IMHO, since

you cannot afterwards determine the context a grob was created in.

Anyway I think a better solution for what you want to achieve would be a 
scheme engraver.
That way you could access context properties, acknowledge NoteHead grobs 
and modify the stencil

as you like.

To be honest, I think that the underlying snippet with all its hardcoded 
paths is not the best way to color note heads with black outline,

because it will break for every change in the note head shape and so on.

I would propose a different solution, shown here as callback function:

%
\version "2.18.2"

\relative c' { c4 d e f }

color-notehead =
#(define-scheme-function (parser location color-outline color-fill 
border-width)

   (color? color? number?)
   (lambda (grob)
 (let* ((stencil-orig (ly:note-head::print grob))
    (scale-factors (cons (- 1 border-width)
 (- 1 border-width
   (grob-interpret-markup grob
 #{
   \markup \halign #LEFT \overlay {
 \with-color $color-outline \halign #CENTER \stencil 
$stencil-orig
 \with-color $color-fill \halign #CENTER \scale 
$scale-factors \stencil $stencil-orig

   }
 #}

\layout {
  \context {
    \Staff
    \override NoteHead.stencil = \color-notehead #black #red #0.3
  }
}


Cheers,
Michael

Am 16.12.2019 um 22:38 schrieb Holleyanne McDaniel:
Hi - I've been working to adapt Colored Noteheads/Outlines 
(http://lsr.di.unimi.it/LSR/Item?id=890) to highlight tonic notes, and 
also be able to color a given voice. I've adjusted the variables to 
let me specify tonic-color and part-color when I call the function, 
and I've narrowed the note comparison to look only at the tonic value. 
(my edited function included below)


There are two things I'm still struggling with. First, I'm currently 
having to include/call a separate function for every single key. (If I 
include them all in a library file, the parser maxes out its memory 
and fails.) In a previous solution that only colored tonic noteheads, 
I used a tonic variable from the EZ numbers engraver, allowing it to 
adapt to key changes on the fly:


(tonic-pitch (ly:context-property context 'tonic))
(tonic-name (ly:pitch-notename tonic-pitch))

Is there a way to use these variables in my current function? If not, 
can I specify the key through a variable when I call it? Every form of 
sending pitch, string, etc. that I've tried has broken the function.
And secondly, I know I'm probably missing something obvious because 
I've made it work in similar settings, but how do I get part-color to 
be an optional variable with a default in the lambda context? Every 
version of (predicate? (predicate? default)) type of definitions I've 
tried also errors out.


coloredNoteheads-c =               %% < rename per key
#(lambda (color-outline line-width tonic-color part-color)
   ;; @var{color-outline} is a boolean for whether
   ;; the outline is colored (#t) or the note head (#f).
   ;; @var{line-width} is a number, the width of
   ;; the outline, 7 is a good default.
   ;; @var{tonic-color} is a color, the key note's
   ;; color or outline.
   ;; @var{part-color} is a color, used if you want a particular
   ;; voice's notes highlighted. If not, set to black.
   (lambda (grob)
     (let* ((fsz  (ly:grob-property grob 'font-size 0.0))
            (mult (magstep fsz))
            (stl empty-stencil)
            (dur-log (ly:grob-property grob 'duration-log))
            (pch (ly:event-property (event-cause 

Identifying Tonic in function & default lambda va

2019-12-16 Thread Holleyanne McDaniel
Hi - I've been working to adapt Colored Noteheads/Outlines (
http://lsr.di.unimi.it/LSR/Item?id=890)  to highlight tonic notes, and also
be able to color a given voice. I've adjusted the variables to let me
specify tonic-color and part-color when I call the function, and I've
narrowed the note comparison to look only at the tonic value.  (my edited
function included below)

There are two things I'm still struggling with. First, I'm currently having
to include/call a separate function for every single key. (If I include
them all in a library file, the parser maxes out its memory and fails.) In
a previous solution that only colored tonic noteheads, I used a tonic
variable from the EZ numbers engraver, allowing it to adapt to key changes
on the fly:

(tonic-pitch (ly:context-property context 'tonic))
(tonic-name (ly:pitch-notename tonic-pitch))

Is there a way to use these variables in my current function? If not, can I
specify the key through a variable when I call it? Every form of sending
pitch, string, etc. that I've tried has broken the function.

And secondly, I know I'm probably missing something obvious because I've
made it work in similar settings, but how do I get part-color to be an
optional variable with a default in the lambda context? Every version of
(predicate? (predicate? default)) type of definitions I've tried also
errors out.

coloredNoteheads-c =   %% < rename per key
#(lambda (color-outline line-width tonic-color part-color)
   ;; @var{color-outline} is a boolean for whether
   ;; the outline is colored (#t) or the note head (#f).
   ;; @var{line-width} is a number, the width of
   ;; the outline, 7 is a good default.
   ;; @var{tonic-color} is a color, the key note's
   ;; color or outline.
   ;; @var{part-color} is a color, used if you want a particular
   ;; voice's notes highlighted. If not, set to black.
   (lambda (grob)
 (let* ((fsz  (ly:grob-property grob 'font-size 0.0))
(mult (magstep fsz))
(stl empty-stencil)
(dur-log (ly:grob-property grob 'duration-log))
(pch (ly:event-property (event-cause grob) 'pitch))
;; get the pitch of current grob
(nnm (ly:pitch-notename pch))
(alt (ly:pitch-alteration pch))
(clr (case nnm
   ((0) (case alt  ;; < change number to tonic key, 0=C

  ((0) tonic-color) ;; <-- change number to tonic
alt
   ;; -1/2 flat, 0 nat, 1/2
sharp
  (else part-color)))

   (else part-color)))

(path-width (case nnm ;; < change number to tonic key
 ((0) (case alt ;; < change to tonic alteration
((0) line-width)

;; if tonic note, path-width = @var{line-width}
(else 1)))
;; else path-width=1 to avoid chunky notes
;; my edit since not every note is colored in this use-case
 (else 1)))
(outline-clr (if color-outline clr part-color))

(note-clr (if color-outline part-color clr)))

;; NO CHANGES REQUIRED PAST THIS POINT FOR DIFFERENT KEYS
;; REMAINDER OF FUNCTION DETERMINES THE PATHS AND DIMENSIONS
;; OF THE ACTUAL NOTES AND OUTLINES
;; UNTOUCHED FROM EXISTING LSR OUTLINE SNIPPET:
;; http://lsr.di.unimi.it/LSR/Item?id=890

 (set! stl

   (cond

;; quarter notes and smaller

((> dur-log 1)

 (grob-interpret-markup grob

#{

  \markup {

\combine

\with-color #outline-clr

\path #(/ path-width 10)

 #'((moveto   0.000  -0.200)

(curveto  0.000  -0.420   0.180  -0.542   0.420
 -0.542)
(curveto  0.800  -0.542   1.318  -0.210   1.318
0.200)
(curveto  1.318   0.420   1.140   0.542   0.890
0.542)
(curveto  0.510   0.542   0.000   0.210   0.000
 -0.200)
(closepath))

\translate #(cons (* 0.0002 path-width) 0)

\with-color #note-clr

\override #'(filled . #t)

\path #0.001

#'((moveto   0.000  -0.200)

   (curveto  0.000  -0.420   0.180  -0.542   0.420
 -0.542)
   (curveto  0.800  -0.542   1.318  -0.210   1.318
0.200)
   (curveto  1.318   0.420   1.140   0.542   0.890
0.542)
   (curveto  0.510   0.542   0.000   0.210   0.000
 -0.200)
   (closepath))

  }

#}

   ))

;; half notes

((= dur-log 1)

 (grob-interpret-markup grob

   #{

 \markup {

\combine

\with-color #outline-clr