additional info for jianpu. 
the output from 7-speech+jianpu_10a_test.ly 


      From: MING TSANG <tsan...@rogers.com>
 To: "imj-...@bluewin.ch" <imj-...@bluewin.ch>; Lilypond-usermailinglist 
<lilypond-user@gnu.org> 
 Sent: Monday, August 21, 2017 9:51 PM
 Subject: Re: Jianpu music notation question
   
forgot to include lilypond user 

      From: TSANGMING <tsan...@rogers.com>
 To: "imj-...@bluewin.ch" <imj-...@bluewin.ch> 
 Sent: Monday, August 21, 2017 6:28 PM
 Subject: Re: Jianpu music notation question
  
#yiv0949541533 #yiv0949541533 -- filtered {panose-1:2 4 5 3 5 4 6 3 2 
4;}#yiv0949541533 filtered {font-family:DengXian;panose-1:2 1 6 0 3 1 1 1 1 
1;}#yiv0949541533 filtered {font-family:Calibri;panose-1:2 15 5 2 2 2 4 3 2 
4;}#yiv0949541533 filtered {font-family:DengXian;panose-1:2 1 6 0 3 1 1 1 1 
1;}#yiv0949541533 p.yiv0949541533MsoNormal, #yiv0949541533 
li.yiv0949541533MsoNormal, #yiv0949541533 div.yiv0949541533MsoNormal 
{margin:0cm;margin-bottom:.0001pt;text-align:justify;text-justify:inter-ideograph;font-size:10.5pt;}#yiv0949541533
 a:link, #yiv0949541533 span.yiv0949541533MsoHyperlink 
{color:blue;text-decoration:underline;}#yiv0949541533 a:visited, #yiv0949541533 
span.yiv0949541533MsoHyperlinkFollowed 
{color:#954F72;text-decoration:underline;}#yiv0949541533 
.yiv0949541533MsoChpDefault {}#yiv0949541533 filtered {margin:72.0pt 72.0pt 
72.0pt 72.0pt;}#yiv0949541533 div.yiv0949541533WordSection1 {}#yiv0949541533 
The following may be of interest to 
youhttps://lists.gnu.org/archive/html/lilypond-user/2015-04/msg01342.html  
Ming.  发送自 Windows 10 版邮件应用  

   

   
\version "2.19"
\language "english"


\include "jianpu10a.ly"
%%%%%%%%%%%%%
% \version "2.18.2"
% also works with 2.19.x and later

#(define (get-keysig-alt-count alt-alist)
   "Return number of sharps/flats in key sig, (+) for sharps, (-) for flats."
   (if (null? alt-alist)
       0
       (* (length alt-alist) 2 (cdr (car alt-alist)))))

#(define (get-major-tonic alt-count)
   "Return number of the tonic note 0-6, as if the key sig were major."
   ;; (alt-count major-tonic)
   ;; (-7 0) (-5 1) (-3 2) (-1 3) (1 4) (3 5) (5 6) (7 0)
   ;; (-6 4) (-4 5) (-2 6) (0 0) (2 1) (4 2) (6 3)
   (if (odd? alt-count)
       (modulo (- (/ (+ alt-count 1) 2) 4) 7)
       (modulo (/ alt-count 2) 7)))

#(define (get-key-alts context)
   "Needed because LilyPond 2.19 and 2.20 has 'keyAlterations
    and 2.18 has 'keySignature for the same context property.
    No way to test for existence of context property..."
   (define key-alts (ly:context-property context 'keyAlterations '()))
   (if (equal? key-alts '())
       (ly:context-property context 'keySignature '())
       key-alts))

#(define (stencil-flip axis stl)
   "Flip stencil @var{stl} in the direction of @var{axis}. 
    @var{axis} is 0 for X, 1 for Y."
   (let* (
           ;; center stl on 0,0 to prepare for flipping,
           ;; and calculate how far it moved.
           (centered-stl (ly:stencil-aligned-to stl axis CENTER))
           (original-ext (ly:stencil-extent stl axis))
           (centered-ext (ly:stencil-extent centered-stl axis))
           (offset (- (car original-ext) (car centered-ext)))

           ;; scale centered-stl using -1 to flip it
           (xy (if (= axis X) '(-1 . 1) '(1 . -1)))
           (flipped-stl (ly:stencil-scale centered-stl (car xy) (cdr xy)))

           ;; restore flipped stl to original position
           (replaced-stl (ly:stencil-translate-axis flipped-stl offset axis)))

     ;; for testing...
     ;; (display original-ext) (display centered-ext)
     ;; (display (ly:stencil-extent replaced-stl axis))(newline)

     replaced-stl))


jianpuMusic =
#(define-music-function (parser location mus) (ly:music?)
   "This music function modifies the music input for better jianpu output."
   (let ((major-tonic-pitch (ly:make-pitch 0 0 0))
         (prev-pitch (ly:make-pitch 0 0 0)))
     (music-map
      (lambda (m)
        (cond

         ;; KEY CHANGE
         ((music-is-of-type? m 'key-change-event)
          (let*
           ((pitch-alist (ly:music-property m 'pitch-alist))
            (key-alts (filter (lambda (a) (not (= 0 (cdr a)))) pitch-alist))
            (keysig-alt-count (get-keysig-alt-count key-alts))
            (major-tonic-number (get-major-tonic keysig-alt-count))
            (tonic (ly:music-property m 'tonic))
            (tonic-num (ly:pitch-notename tonic))
            ;; mode 1-7, 1=major 6=minor
            (mode (+ 1 (modulo (- tonic-num major-tonic-number) 7))))

           (set! major-tonic-pitch
                 (ly:make-pitch 0
                   major-tonic-number
                   (or (assoc-ref key-alts major-tonic-number) 0)))
           ;; store the actual key of the music for use in jianpu key signatures
           (ly:music-set-property! m 'jianpu-key-sig (cons mode tonic))

           ;; convert the key signature in effect to c major
           (ly:music-set-property! m 'pitch-alist '((0 . 0) (1 . 0) (2 . 0) (3 . 0) (4 . 0) (5 . 0) (6 . 0)))
           (ly:music-set-property! m 'tonic (ly:make-pitch 0 0 0))
           ))

         ;; REST AND MULTI-MEASURE REST
         ((or (music-is-of-type? m 'rest-event)
              (music-is-of-type? m 'multi-measure-rest))
          (let ((dur (ly:moment-main (ly:music-duration-length m))))
            (if (>= dur 1/2)
                ;; split whole and half rests into quarter notes
                (let ((q (make-music 'NoteEvent
                           'duration (ly:make-duration 2 0 1)
                           'jianpu-rest #t)))
                  ;; double dotted half rest is special case
                  ;; TODO: generalize this for triple dots, other durations, etc.?
                  (if (= dur 7/8)
                      (let ((q-dotted (ly:music-deep-copy q)))
                        (ly:music-set-property! q-dotted 'duration (ly:make-duration 2 1 1))
                        (set! m (make-sequential-music (append (make-list 2 q) (list q-dotted)))))
                      ;; else
                      (set! m (make-sequential-music (make-list (* 4 dur) q)))))

                ;; shorter rests are just converted into notes without pitches
                ;; and with a jianpu-rest property added
                (begin
                 (ly:music-set-property! m 'name 'NoteEvent)
                 (ly:music-set-property! m 'types
                   (append
                    (delete 'rest-event (ly:music-property m 'types))
                    '(note-event melodic-event)))
                 (ly:music-set-property! m 'jianpu-rest #t)
                 ))))

         ;; NOTE
         ((music-is-of-type? m 'note-event)
          ;; handle pitchless note events and transpose pitches to c major
          ;; which gives us correct accidentals and octaves "for free"
          (if (ly:pitch? (ly:music-property m 'pitch))
              (begin
               (ly:music-set-property! m 'pitch
                 (ly:pitch-transpose (ly:music-property m 'pitch)
                   (ly:pitch-negate (ly:pitch-diff major-tonic-pitch (ly:make-pitch 0 0 0)))))
               (set! prev-pitch (ly:music-property m 'pitch)))
              ;; else
              (ly:music-set-property! m 'pitch prev-pitch))

          (let* ((octave (ly:pitch-octave (ly:music-property m 'pitch)))
                 (octave-dir (if (> octave 0) 1 -1))
                 (artics (ly:music-property m 'articulations '()))
                 (dur (ly:moment-main (ly:music-duration-length m)))
                 (dot (ly:stencil-translate
                       (make-circle-stencil 0.2 0.001 #t)
                       (cons 0.6 0)))
                 (dot-two (ly:stencil-stack dot Y DOWN dot 0.5 0))
                 (dot-three (ly:stencil-stack dot-two Y DOWN dot 0.5 0))
                 (dot-four (ly:stencil-stack dot-three Y DOWN dot 0.5 0)))

            ;; add octave dot markups as articulations
            ;; from jianpu-ly python script: "-\tweak #'X-offset #0.6 _."
            (if (not (= 0 octave))
                (ly:music-set-property! m 'articulations
                  (append artics
                    (list
                     (make-music 'TextScriptEvent
                       'direction octave-dir
                       'text (markup #:stencil
                               (case (abs octave)
                                 ((1) dot)
                                 ((2) dot-two)
                                 ((3) dot-three)
                                 ((4) dot-four)
                                 (else dot-four)
                                 )))))))

            ;; split whole and half notes into quarter notes, some dashed
            (if (>= dur 1/2)
                (let* ((dash-num (+ -1 (* 4 dur)))
                       (q-dur (ly:make-duration 2 0 1))
                       (q (make-music 'NoteEvent
                            'duration q-dur
                            'pitch (ly:music-property m 'pitch)
                            'jianpu-dash-note #t)))

                  (ly:music-set-property! m 'duration q-dur)

                  (if (= dash-num 5/2)
                      ;; special fix for double-dotted half note
                      ;; TODO: generalize this for triple dots, other durations, etc.?
                      (let ((q-dotted (ly:music-deep-copy q)))
                        (ly:music-set-property! q-dotted 'duration (ly:make-duration 2 1 1))
                        (set! m (make-sequential-music
                                 (append (list m q) (list q-dotted)))))
                      ;; else
                      (set! m (make-sequential-music
                               (append (list m) (make-list dash-num q)))))
                  )))))
        m)
      mus)))


% Note: when checking custom event properties like jianpu-rest or
% jianpu-key-sig we have to use (if (equal? #t jianpu-rest) ...
% and not (if jianpu-rest ...  the latter results in "false positives".


#(define Jianpu_note_head_engraver
   (make-engraver
    (acknowledgers
     ((note-head-interface engraver grob source-engraver)
      ;; make sure \omit is not in effect (stencil is not #f)
      (if (ly:grob-property-data grob 'stencil)
          (let* ((staff-context (ly:translator-context engraver))
                 (event (event-cause grob))
                 (jianpu-dash-note (ly:event-property event 'jianpu-dash-note)))
            (if (equal? #t jianpu-dash-note)
                (ly:grob-set-property! grob 'stencil
                  (ly:stencil-translate
                   (make-connected-path-stencil '((1 0)) 0.3 1 1 #f #f)
                   (cons 0 1)))
                ;; else create number stencil based on the scale degree of the note
                ;; TODO: handle notes without pitches that aren't jianpu-rests
                (let*
                 ((grob-pitch (ly:event-property event 'pitch))
                  (note-number
                   (if (ly:pitch? grob-pitch)
                       (ly:pitch-notename grob-pitch) #f))
                  (jianpu-rest (ly:event-property event 'jianpu-rest))
                  (glyph-string
                   ;; check jianpu-rest first, because apparently
                   ;; sometimes there is a note-number for rests.
                   (if (equal? #t jianpu-rest)
                       "zero"
                       (if (number? note-number)
                           (case (+ 1 note-number)
                             ((1) "one")
                             ((2) "two")
                             ((3) "three")
                             ((4) "four")
                             ((5) "five")
                             ((6) "six")
                             ((7) "seven")
                             (else "zero"))
                           #f)))
                  (stl
                   (if (string? glyph-string)
                       (grob-interpret-markup grob
                         (markup #:musicglyph glyph-string)))))

                 (ly:grob-set-property! grob 'stencil stl)
                 ))))))))


#(define Jianpu_flag_engraver
   (make-engraver
    (acknowledgers
     ((flag-interface engraver grob source-engraver)
      ;; make sure \omit is not in effect (stencil is not #f)
      (if (ly:grob-property-data grob 'stencil)
          (let* ((glyph-name (ly:grob-property grob 'glyph-name))
                 (padding 0.35)
                 ;; TODO: width is hard-coded, would be better to match note-head width
                 ;; TODO: stencil creation could be coded better
                 (flag-one (make-connected-path-stencil '((1.2 0)) 0.15 1 1 #f #f))
                 (flag-two (ly:stencil-stack flag-one Y DOWN flag-one padding 0))
                 (flag-three (ly:stencil-stack flag-two Y DOWN flag-one padding 0))
                 (flag-four (ly:stencil-stack flag-three Y DOWN flag-one padding 0))
                 (flag-five (ly:stencil-stack flag-four Y DOWN flag-one padding 0))
                 (new-stl (cond
                           ((string= glyph-name "flags.d3") flag-one)
                           ((string= glyph-name "flags.d4") flag-two)
                           ((string= glyph-name "flags.d5") flag-three)
                           ((string= glyph-name "flags.d6") flag-four)
                           ((string= glyph-name "flags.d7") flag-five)
                           (else empty-stencil))))

            (ly:grob-set-property! grob 'stencil new-stl)
            (ly:grob-set-property! grob 'Y-offset -2)
            ;; TODO: are these needed?
            ;; (ly:grob-set-property! grob 'X-extent
            ;;  (ly:stencil-extent (ly:grob-property grob 'stencil) X))
            ;; (ly:grob-set-property! grob 'Y-extent
            ;;  (ly:stencil-extent (ly:grob-property grob 'stencil) Y))
            ))))))


#(define (jianpu-beam-adjust grob)
   "Adjusts the width etc. of beams."
   ;; We calculate the amount to scale based on width of beam
   ;; TODO: improve this, maybe by using stems
   (let* ((x-ext (interval-length (ly:stencil-extent (ly:grob-property grob 'stencil) X)))
          (x-scale (+ 1 (/ 1.4 x-ext))))
     ;; (display x-ext)(newline)
     (ly:grob-set-property! grob 'stencil
       ;; (ly:stencil-translate
       (stencil-flip Y
         (ly:stencil-scale
          (ly:grob-property grob 'stencil)
          x-scale 1))
       ;; (cons 0 0))
       )))


#(define Jianpu_key_engraver
   (let ((current-key-sig (cons 1 (ly:make-pitch 0 0 0))))
     (make-engraver
      (acknowledgers
       ((key-signature-interface engraver grob source-engraver)
        ;; make sure \omit is not in effect (stencil is not #f)
        (if (ly:grob-property-data grob 'stencil)
            (let* ((event (event-cause grob))
                   (jianpu-key-sig
                    (if event
                        (ly:event-property event 'jianpu-key-sig)
                        current-key-sig))
                   (tonic-num (car jianpu-key-sig))
                   (tonic-pitch (cdr jianpu-key-sig))
                   (key-sig-number-string (ly:number->string tonic-num))
                   (key-sig-note
                    (case (ly:pitch-notename tonic-pitch)
                      ((0) "C")
                      ((1) "D")
                      ((2) "E")
                      ((3) "F")
                      ((4) "G")
                      ((5) "A")
                      ((6) "B")
                      (else "X")))
                   (key-sig-alt
                    (case (ly:pitch-alteration tonic-pitch)
                      ((1/2) #{ \markup \sharp #})
                      ((-1/2) #{ \markup \flat #})
                      (else ""))))

              (set! current-key-sig jianpu-key-sig)

              (ly:grob-set-property! grob 'stencil
                (grob-interpret-markup grob
                  ;; TODO: scale the flat or sharp size, based on current font size
                  (markup key-sig-number-string "=" key-sig-alt key-sig-note)
                  )))))))))


% Custom "JianpuStaff" Context

\layout {
  \context {
    % \Staff lets us start with all standard staff settings
    \Staff
    % \name gives the custom staff context its name
    \name JianpuStaff
    % \alias Staff tells LilyPond that commands that work on a standard
    % Staff context should also work with this custom context
    \alias Staff
    % customizations
    \consists \Jianpu_note_head_engraver
    \consists \Jianpu_flag_engraver
    \consists \Jianpu_key_engraver

    \override Beam.after-line-breaking = #jianpu-beam-adjust
    \override KeySignature.break-visibility = ##(#f #f #f)

    \override Accidental.font-size = #-2.5
    \override Clef.stencil = ##f
    \override StaffSymbol.line-count = #0
    \override BarLine.bar-extent = #'(-2 . 2)
    \override TimeSignature.style = #'numbered
    % \override Stem.transparent = ##t
    \override Stem.length = #0
    \override Stem.length-fraction = #0
    \override NoteHead.Y-offset = #-1
    \override Beam.transparent = ##f
    \override Stem.direction = #DOWN
    \override Beam.beam-thickness = #0.15
    \override Beam.length-fraction = #0.5
    \override Tie.staff-position = #2.5
    \override TupletBracket.bracket-visibility = ##t
    \tupletUp
    \slurUp
    % \hide Stem
    \omit Stem
    \override Dots.staff-position = #2
  }
  % define the "parent" contexts that will accept the custom context
  \context { \Score \accepts JianpuStaff }
  \context { \ChoirStaff \accepts JianpuStaff }
  \context { \GrandStaff \accepts JianpuStaff }
  \context { \PianoStaff \accepts JianpuStaff }
  \context { \StaffGroup \accepts JianpuStaff }
}

% And for MIDI
% to avoid warnings it has to be defined for each type of output desired
% but we actually can't use midi with the jianpu music function, so this
% is rather pointless... leaving it in for now.
\midi {
  \context {
    \Staff
    \name JianpuStaff
    \alias Staff
  }
  % since the customizations are for visual output only,
  % there is no need to include them for midi
  \context { \Score \accepts JianpuStaff }
  \context { \ChoirStaff \accepts JianpuStaff }
  \context { \GrandStaff \accepts JianpuStaff }
  \context { \PianoStaff \accepts JianpuStaff }
  \context { \StaffGroup \accepts JianpuStaff }
}



%  }
%%%%%%%%%%%%%%%%%%%
  
\header {
  title = "十架七言"
  subtitle = "7 speech"
  % Remove default LilyPond tagline
  tagline = ##f
}

\paper {
  #(set-paper-size "letter")
}

\layout {
  \context {
    \Voice
    \consists "Melody_engraver"
    \override Stem #'neutral-direction = #'()
  }
}

globald = {
  \key d \major
  \numericTimeSignature
  \time 3/4
  \tempo 4=100
}


\include "include_lyndon-specific.ly"

melodyd =   {  
   
  fs'2. | %m01
  e'2 a'8. g'16 |%m002
  fs'4 fs'2 |%m03
  d'4 d''4 cs''8.( b'16) %m04
  a'2 b'8. g'16 |\break %m05
  fs'2 e'8 fs'8 |%m06
  e'8 b8 d'2 |%m07
  a'4 fs'2 |%m08
  e'4 fs'4  a'8( g'8) |%m09
  fs'2 d''4 | \break %m10
  cs''8( d''8) e''8( d''8) cs''8( b'8) |%m11
  a'2. |%m12
  d'4 d''2 |%m13
  d''4 cs''4 b'8 a'8 |%m14
  fs'2. |\break %m15
  d'4 b'2 |%m16
  b'4 a'4 g'8 fs'8 |%m17
  e'2 a'8( g'8) |%m18
  fs'2 fs'8( e'8) |%m19
  d'2 d''8( cs''8) |\break %m20
  b'2 b'8( a'8) |%m21
  g'2 fs'4 |%m22
  e'8 d' cs'( e') cs'( d') |%m23
  b2. |%m24
  b2 cs'8( e'16 d'16) | \break %m25
  b2 \tuplet 3/2{g'8( b'  g')} |%m26
  fs'2 r4 |%m27
  fs'8 fs'4~8 r4 |%m28
  b'4 a'8( g'8) fs'4 |%m29
  e'8 d' cs' e' d' cs' |  %m30
  b2. \bar"|."
  \label #'lastPage
}




verse = \lyricmode {
  父 啊! 赦 免 他 們, 因 為 他 們 所 作 的, 他 們 不 曉 得. 
  %{我 實 在 告 訴 你, %} 今 日 你 要 同 我 在 樂 園 裡 了. 
  母 親 看 你 的 兒 子, (門 徒) 看 你 的 母 親. 
  我 的 神 哪! 我 的 神 哪! 為 甚 麽 離 棄 我!
  我 渴 了!
  成 了!
  父 啊! 我 將 我 靈 魂 交 在 祢 手 裡.
  
}
sk = \tag "SK" {\skip1}
verseSK = \lyricmode {
  父 \sk \sk 啊! \sk 赦 免 他 們, \sk  因 為 他 們 \sk  所 作 的, \sk  他 們 不 曉 得. \sk  
  %{我 實 在 告 訴 你, %} 今 日 \sk  你 要 同 我 \sk  在 樂 園 裡 了. \sk  \sk  
  母 親 \sk  看 你 的 兒 子, \sk  \sk  (門 徒) \sk  看 你 的 母 親. \sk    
  我 的 \sk  神 哪! \sk  我 的 \sk  神 哪! \sk  為 甚 麽 離 棄 我! \sk  \sk 
  我 \sk  渴 了! \sk 
  成 了! \sk  \sk 
  父 啊! \sk  我 將 我 靈 魂 交 在 祢 手 裡.
}
verseSolfege = \lyricmode {
  父2 啊!2 赦8. 免16 他4 們,2 因4 為4 他8.~16 們2 所8. 作16 的,2 他8 們8 不8 曉8 得.2 
  %{我 實 在 告 訴 你, %} 今4 日2 你4 要4 同8~8 我2 在4 樂8~8 園8~8 裡8~8 了.2. 
  母4 親2 看4 你4 的8 兒8 子.2. (門4 徒)2 看4 你4 的8 母8 親.2 
  我8~8 的2 神8~8 哪!2 我8~8 的2 神8~8 哪!2 為4 甚8 麽8~8 離8~8 棄8~8  我2.
  我2  渴8~16~16 了!2
  成\tuplet3/2{8( 8 8)} 了2 s4
  父8 啊!4~8 s4 我4 將8~8 我4 靈8 魂8 交8 在8 祢8 手8 裡2.
}
verseJ = \lyricmode {
  父 \skip1 \skip1 啊! \skip1 赦 免 他 們, \skip1  因 為 他 們 \skip1  所 作 的, \skip1  他 們 不 曉 得. \skip1  
  %{我 實 在 告 訴 你, %} 今 日 \skip1  你 要 同 我 \skip1  在 樂 園 裡 了. \skip1  \skip1  
  母 親 \skip1  看 你 的 兒 子, \skip1  \skip1  (門 徒) \skip1  看 你 的 母 親. \skip1    
  我 的 \skip1  神 哪! \skip1  我 的 \skip1  神 哪! \skip1  為 甚 麽 離 棄 我! \skip1  \skip1 
  我 \skip1  渴 了! \skip1 
  成 了! \skip1  \skip1 
  父 啊! \skip1  我 將 我 靈 魂 交 在 祢 手 裡.
  
}


\score { 
  <<  
  
  \new JianpuStaff \jianpuMusic \new Voice = solfege { \globald \melodyd }
  \new Lyrics \keepWithTag "SK" \lyricsto solfege {     \verseSK    }
  
  \new Staff  \new Voice = number    { \globald \melodyd }
  %\new Lyrics \removeWithTag "SK" \lyricsto number {  \verseSK } 
  >>
  \layout { }
  %\midi { }
}

\book {
  \bookOutputSuffix "midi"
 \score { 
  <<  
    %\jianpuVoice
    %\new JianpuStaff \jianpuMusic         {  \globald \melodyd }
      
    %\new ChordNames \chordNames
    \new Staff     { \globald \melodyd }
    %\addlyrics { \verse }
  >>
  %\layout { }
  \midi { }
 }
}

_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user

Reply via email to