Hi,

2018-04-02 6:32 GMT+02:00 brob2684 <bennrobert...@hotmail.com>:
> Hi Harm,
>
> I hadn't really thought about no key signature as being an issue, but I can
> certainly see how it can cause confusion.
>
> I think you are correct in suggesting "no key signature present" would be
> the appropriate output, although I'll admit I'm unlikely to ever come across
> such a case in my use of lilypond.

Well, even your first musical example has no (initial) KeySignature ;)

>>> melody = \relative c'' {
>>>   \time 4/4
>>>   c1 \key d \major d \key e \major e \key f \major f
>>> }

For the arbitrary reuse of a variable, this variable needs to be
defined at toplevel.
It's possible to update such a toplevel-variable by using an engraver,
though if you clear that variable in the engraver the value(s)/entries
are only available _in_ the score where the engraver works.
For multiple scores in the same file this means: if you don't clear it
then the values will accumulate (or override themselves).
Additionally the engraver updates it too late to have direct access to
the new values for other toplevel-markups.

So I decided to let the key-sig-names accumulate in a toplevel-list,
numbering them. Also, I wrote a markup-command where you need to
select the correct entry by using a number. A markup-command is
processed late enough.

Code attached, note the comments.

HTH,
  Harm
\version "2.19.81"

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% After:
%%%%
%%%% http://lsr.di.unimi.it/LSR/Item?id=856
%%%% see also lists.gnu.org/archive/html/lilypond-user/2013-12/msg00828.html
%%%% by Paul Morris

%% tonic-num: number of the tonic note 0-6, C=0, B=6
%% acc-type: the accidental sign type, 1/2=sharp, -1/2=flat
%% acc-count: the number and type of accidentals in the key signature
%%                  values are: -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7
%%                  (negative = flats, positive = sharps)
%% tonic-acc: #f if the tonic note is not sharp or flat, otherwise a pair
%% maj-num: number of the tonic note 0-6, if the key sig were major
%% mode-num: number of the mode 0-6
%% txt-size: size of key name text
%% mult: for correct resizing when the staff is resized

%% This list will be filled by the engraver and 
%% 'replace-key-sig-name'-markup-command accesses it
#(define key-signature-list '())

#(define update-key-signature-list
;; Update `key-signature-list' by a pair containing a number and `entry'
;; The numbers increase.
  (lambda (entry)
    (set! key-signature-list
          (cons 
            (cons (1+ (length key-signature-list)) entry)
            key-signature-list))))

#(define (initial-moment? ctx)
  "Is current-moment the @code{ZERO-MOMENT} or before?"
  (not
    (ly:moment<? 
      ZERO-MOMENT
      (ly:context-current-moment ctx))))

#(define Store_initial_key_engraver
;; This engraver stores initial key-signatures in `key-signature-list'.
;; If no key-signature is present some text will be taken.
;; Because `key-signature-list' is a toplevel-definition all initial 
;; key-signatures of all scores of a file will get an entry there. 
;; To distuingish them they are numbered.
  (lambda (context)
    (let ((initial-key #f))
      (make-engraver
        ;; If no initial key-signature is present let `initial-key' unchanged.
        ;; An entry in `key-signature-list' will then be done during th
        ;; `finalize'-step.
        ;; Otherwise `key-signature-list' will be updated in `acknowledgers'.
        (listeners
          ((key-change-event engraver ev)
            (if (initial-moment? context)
                (set! initial-key #t))))
        (acknowledgers
         ((key-signature-interface engraver grob source-engraver)
          ;; If key cancellation then do nothing (TODO needed?).
          ;; If we are at the very beginning, update `key-signature-list'
          (if (and (initial-moment? context) 
                   (not (eq? 'KeyCancellation (grob::name grob))))
              (let* ((tonic-pitch (ly:context-property context 'tonic))
                     (tonic-num (ly:pitch-notename tonic-pitch))
                     (acc-list (ly:grob-property grob 'alteration-alist))
                     (acc-type (if (null? acc-list)
                                   0 
                                   (cdr (list-ref acc-list 0))))
                     (acc-count (* (length acc-list) (if (< acc-type 0) -1 1)))
                     (maj-num 
                       (case acc-count
                         ((0) 0)
                         ((1) 4) ((2) 1) ((3) 5) ((4) 2) ((5) 6) ((6) 3) ((7) 0)
                         ((-1) 3) ((-2) 6) ((-3) 2) ((-4) 5) ((-5) 1) ((-6) 4) 
                         ((-7) 0)))
                     (mode-num (modulo (- tonic-num maj-num) 7))
                     ;; Select the tonic-name
                     (key-letter (case tonic-num
                                   ((0) "C" ) ((1) "D" ) ((2) "E" ) ((3) "F" )
                                   ((4) "G" ) ((5) "A" ) ((6) "B" )))
                     (mult (magstep (ly:grob-property grob 'font-size 0.0)))
                     ;; format accidentals for text
                     (txt-sharp 
                       #{ 
                         \markup {
                           \translate #(cons (* mult -0.3) (* mult 0.8))
                           \magnify #(* mult 0.9) 
                           \sharp 
                         } 
                       #})
                     (txt-flat 
                       #{ 
                         \markup {
                           \translate #(cons (* mult -0.2) (* mult 0.4))
                           \magnify #(* mult 0.9) 
                           \flat
                         } 
                       #})
                     ;; select the final accidental
                     (tonic-acc (if (pair? (assq tonic-num acc-list))
                                    (if (= acc-type 0.5) txt-sharp txt-flat)
                                    ""))
                     ;; select the scale-name
                     (key-mode (case mode-num
                                 ((0) "Major") ((1) "Dorian") ((2) "Phrygian") 
                                 ((3) "Lydian") ((4) "Mixolydian") ((5) "Minor") 
                                 ((6) "Locrian"))))
                (update-key-signature-list 
                  (list key-letter tonic-acc key-mode))))))
        ;; If not initial KeySignature is set, do an entry here.
        ((finalize engraver)
          (if (not initial-key)
              (update-key-signature-list (list "no")))
          (set! initial-key #f))))))
    
%% We need to go for a markup-command, `key-signature-list' is updated too late
%% to acces it more directly.
#(define-markup-command (replace-key-sig-name layout props which arg)
  (index? markup?)
  #:category font
  "
Replaces \"key-signature-name\" in @var{arg} by an entry from 
@code{key-signature-list}, the relevant entry needs to be specified by 
@var{which}"
  (interpret-markup
    layout
    props
    (if (string=? (markup->string arg) "key-signature-name")
        (make-line-markup (assoc-get which key-signature-list (list "??")))
        arg)))
                
\layout {
  \context {
    \Staff
    \consists \Store_initial_key_engraver
  }
}

%%%%%%%%%%%%%%%%%%%%%%%%%
%% EXAMPLES
%%%%%%%%%%%%%%%%%%%%%%%%%

txt =
\markuplist {
  Some text later that states that the above piece starts in key-signature-name 
  key
}

lazySpacer =
\markup \column { \vspace #1 \draw-hline }

\new Staff \relative f'' {
  \key cis \minor
  c1 d
  \key b \minor
  a1
}

\markup \replace-key-sig-name #1 \txt
\lazySpacer

\new Staff \relative f'' {
  \key gis \minor
  c1 d
  \key d \major
  a1
}

\markup \replace-key-sig-name #2 \txt
\lazySpacer

\new Staff \relative f'' {
  c1 d
  a1
}

\markup \replace-key-sig-name #3 \txt
\lazySpacer

\new Staff \relative f'' {
  \key c \major
  c1 d
  a1
}

\markup \replace-key-sig-name #4 \txt
\lazySpacer

\new Staff \relative f'' {
  \key as \major
  c1 d
  \key d \major
  a1
}

\markup \replace-key-sig-name #5 \txt
\lazySpacer
_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user

Reply via email to