2017-04-21 17:40 GMT+02:00 Kieren MacMillan <kieren_macmil...@sympatico.ca>:
> Hello all,
>
> Is there an easy markup tracking/letterspacing function floating around out 
> there? The last time I needed to adjust letterspacing (for a style demo), I 
> simply wrote e.g.
>
>   \markup \override #'(word-space . 0) \line { l e t t e r s p a c i n g }
>   \markup \override #'(word-space . 0.2) \line { l e t t e r s p a c i n g }
>   \markup \override #'(word-space . 2) \line { l e t t e r s p a c i n g }
>
> If somebody out there has built, or could help me build, a real letterspacing 
> function — or, I suppose better yet, add letterspacing as a parameter to the 
> underlying markup code — I’d appreciate it.
>
> Thanks,
> Kieren.



Hi Kieren,

the attached was once coded in the now down German Forum by Arnold.
Please be aware of the problems, let me quote the comment for
'unicode-diacritics':
"
; These are the UNICODE ranges of the diacritical symbols, which
; should not be insulated form their predestinating glyph.
; Look at the code charts at www.unicode.org for more information.
; As long as this table is entered manually there is a high risk of errors.
; This list (ascending order) tends to be incomplete
"


Furthermore I tested with my experimental guile-2.2.1-lilypond-build:

\markup \box #(map string (string->list "名字äüö\\letterspacing"))
\markup #(map string (string->list "名字äüö\\letterspacing"))
\markup
  \override #'(word-space . -0.2)
  \line #(map string (string->list "名字äüö\\letterspacing"))
\markup
  \override #'(word-space . 2)
  \line #(map string (string->list "名字äüö\\letterspacing"))

Returning the attached png.
Though, don't try it with guilev1-lilypond.
It will return wagonloads of pango-warnings and bad output...


HTH,
  Harm
\version "2.18.2"

#(define (utf-8-string->wide-char-list str)
"
 Convert a UTF-8 byte string into an list with integer representing the 
 UNICODE character codes
"
  (let ((erg '())
        (mult 1)
        (sum 0))
        
  (for-each 
    (lambda (single-byte-char)
      (let ((numeric (char->integer single-byte-char)))
      (if (< numeric #x80)
       (begin ; 7-Bit-ASCII stand alone character
         (if (not (equal? mult 1)) 
           (begin
             (ly:warning 
               "utf-8-string->wide-char-list: UTF-8-string out of sequence!")
             (set! mult 1) (set! sum 0)))
         (set! erg (cons numeric erg)))
       (if (< numeric #xc0)
        (begin ; 10. ..... = UTF-8 expansion byte
          (set! sum (+ sum (* mult (- numeric #x80))))
          (set! mult (* 64 mult)))
        (if (< numeric #xe0)
         (begin ; 110. .... = UTF-8 start of two byte sequence
           (if (not (equal? mult 64))
            (ly:warning 
              "utf-8-string->wide-char-list: UTF-8-string out of sequence!")
            (begin
              (set! sum (+ sum (* mult (- numeric #xc0))))
              (set! erg (cons sum erg))))
           (set! mult 1) (set! sum 0))
         (if (< numeric #xf0)
          (begin ; 1110 .... = UTF-8 start of three byte sequence
           (if (not (equal? mult 4096))
            (ly:warning 
              "utf-8-string->wide-char-list: UTF-8-string out of sequence!")
            (begin
              (set! sum (+ sum (* mult (- numeric #xe0))))
              (set! erg (cons sum erg))))
           (set! mult 1) (set! sum 0))
          (if (< numeric #xf8)
           (begin ; 1111 0... = UTF-8 start of four byte sequence
            (if (not (equal? mult 262144))
             (ly:warning 
               "utf-8-string->wide-char-list: UTF-8-string out of sequence!")
             (begin
               (set! sum (+ sum (* mult (- numeric #xf0))))
               (set! erg (cons sum erg))))
            (set! mult 1) (set! sum 0))
           (begin ;; This would be the header of a UTF-8 encoding of an 
                  ;; UNICODE character with more than 21 bits - this
                  ;; does not exist!
             (ly:warning 
               "utf-8-string->wide-char-list: UTF-8-string out of sequence!")
             (set! mult 1) (set! sum 0)))))))))
    (reverse (string->list str)))
  erg))

#(define unicode-diacritics 
; These are the UNICODE ranges of the diacritical symbols, which
; should not be insulated form their predestinating glyph.
; Look at the code charts at www.unicode.org for more information.
; As long as this table is entered manually there is a high risk of errors.
; This list (ascending order) tends to be incomplete
 '(                         
   ; Combining Diacritical Marks
   ( #x0300 . #x036f )
   ; Cyrillic
   ( #x0483 . #x0489 )
   ; Hebrew
   ( #x0591 . #x05bd )
   ( #x05bf . #x05bf )
   ( #x05c1 . #x05c2 )
   ( #x05c4 . #x05c5 )
   ( #x05c7 . #x05c7 )
   ; Arabic
   ( #x0610 . #x061a )
   ( #x064b . #x065f )
   ( #x0670 . #x0670 )
   ( #x06d6 . #x06dc )
   ( #x06df . #x06e4 )
   ( #x06ea . #x06ed )
   ; Syriac
   ( #x0711 . #x0711 )
   ( #x0730 . #x074a )
   ; Thaana
   ( #x07a6 . #x07b0 )
   ; NKo
   ( #x07eb . #x07f3 )
   ; Samaritan
   ( #x0816 . #x0823 )
   ( #x0825 . #x0827 )
   ( #x0829 . #x082d )
   ; Mandaic
   ( #x0859 . #x085b )
   ; Arabic Extended-A
   ( #x08e4 . #x08fe )
   ; Devanagari
   ( #x0900 . #x0903 )
   ( #x093a . #x093c )
   ( #x0934 . #x094f )
   ( #x0951 . #x0957 )
   ( #x0962 . #x0963 )
   ; Bengali
   ( #x0981 . #x0983 )
   ( #x09bc . #x09bc )
   ( #x09be . #x09cd )
   ( #x09d7 . #x09d7 )
   ( #x09e2 . #x09e3 )
   ; Gurmukhi
   ( #x0a01 . #x0a03 )
   ( #x0a3c . #x0a3c )
   ( #x0a3e . #x0a42 )
   ( #x0a47 . #x0a48 )
   ( #x0a4b . #x0a4d )
   ( #x0a51 . #x0a51 )
   ( #x0a70 . #x0a71 )
   ( #x0a75 . #x0a75 )
   ; Gujarati
   ( #x0a81 . #x0a83 )
   ( #x0abc . #x0abc )
   ( #x0abe . #x0acd )
   ( #x0ae2 . #x0ae4 )
   ; Oriya
   ( #x0b01 . #x0b03 )
   ( #x0b3c . #x0b3c )
   ( #x0b3e . #x0b56 )
   ( #x0b62 . #x0b64 )
   ; Tamil
   ( #x0b82 . #x0b82 )
   ( #x0bb4 . #x0bcd )
   ( #x0bd7 . #x0bd7 )
   ; Telugu
   ( #x0c01 . #x0c03 )
   ( #x0c3e . #x0c56 )
   ( #x0c62 . #x0c63 )
   ; Kannada
   ( #x0c82 . #x0c83 )
   ( #x0cbc . #x0cd6 )
   ( #x0ce2 . #x0ce3 )
   ; Malayalam
   ( #x0d02 . #x0d03 )
   ( #x0d3e . #x0d4d )
   ( #x0d57 . #x0d57 )
   ( #x0d62 . #x0d63 )
   ; Sinhala
   ( #x0d82 . #x0d83 )
   ( #x0dca . #x0df3 )
   ; Thai
   ( #x0e31 . #x0e31 )
   ( #x0e34 . #x0e3a )
   ( #x0e47 . #x0e4e )
   ; Lao
   ( #x0eb1 . #x0eb1 )
   ( #x0eb4 . #x0ebc )
   ( #x0ec8 . #x0ecd )
   ; Tibetan
   ( #x0f18 . #x0f19 )
   ( #x0f35 . #x0f35 )
   ( #x0f37 . #x0f37 )
   ( #x0f39 . #x0f39 )
   ( #x0f3e . #x0fef )
   ( #x0f71 . #x0f84 )
   ( #x0f86 . #x0f87 )
   ( #x0f8d . #x0fbc )
   ; Myanmar
   ( #x102b . #x1039 )
   ( #x103a . #x103e )
   ( #x1056 . #x1059 )
   ( #x105e . #x1060 )
   ( #x1062 . #x1064 )
   ( #x1067 . #x106d )
   ( #x1071 . #x1074 )
   ( #x1082 . #x108d )
   ( #x108f . #x108f )
   ( #x109a . #x109d )
   ; Tagalog
   ( #x1712 . #x1714 )
   ; Hanunoo
   ( #x1732 . #x1734 )
   ; Buhid
   ( #x1752 . #x1753 )
   ; Tagbanwa
   ( #x1772 . #x1773 )
   ; Khmer
   ( #x17b6 . #x17d1 )
   ( #x17d3 . #x17d3 )
   ( #x17dd . #x17dd )
   ; Limbu
   ( #x1920 . #x193b )
   ; New Tai Lue
   ( #x19b0 . #x19c0 )
   ( #x19c8 . #x19c9 )
   ; Buginese
   ( #x1a17 . #x1a1b )
   ; Tai Tahm
   ( #x1a55 . #x1a7f )
   ; Balinese
   ( #x1b00 . #x1b04 )
   ( #x1b34 . #x1b44 )
   ( #x1b6b . #x1b73 )
   ; Sundanese
   ( #x1b80 . #x1b82 )
   ( #x1ba1 . #x1baa )
   ( #x1bac . #x1bad )
   ; Batak
   ( #x1be6 . #x1bf3 )
   ; Lepcha
   ( #x1c24 . #x1c37 )
   ; Vedic Extensions
   ( #x1cd0 . #x1ce8 )
   ( #x1ced . #x1ced )
   ( #x1cf2 . #x1cf4 )
   ; Combining Diacritical Marks Supplement
   ( #x1dc0 . #x1dff )
   ; Combining Diacritical Marks for Symbols
   ( #x20d0 . #x20ff )
   ; Coptic
   ( #x2cef . #x2cf1 )
   ; Cyrillic Extended-A
   ( #x2d40 . #x2dff )
   ; Hiragana
   ( #x3099 . #x309a )
   ; Cyrillic Extended-B
   ( #xa66f . #xa67d )
   ( #xa69f . #xa69f )
   ; Syloti Nagri
   ( #xa802 . #xa802 )
   ( #xa806 . #xa806 )
   ( #xa80b . #xa80b )
   ( #xa823 . #xa827 )
   ; Saurashtra
   ( #xa880 . #xa881 )
   ( #xa8b4 . #xa8c4 )
   ; Devanagari Extended
   ( #xa8e0 . #xa8f1 )
   ; Kayah Li
   ( #xa926 . #xa92d )
   ; Rejang
   ( #xa947 . #xa953 )
   ; Javanese
   ( #xa980 . #xa983 )
   ( #xa9b3 . #xa9c0 )
   ; Cham
   ( #xaa29 . #xaa36 )
   ( #xaa43 . #xaa43 )
   ( #xaa4c . #xaa4d )
   ; Myanmar Extended-A
   ( #xaa7b . #xaa7b )
   ; Tai Viet
   ( #xaab0 . #xaab0 )
   ( #xaab2 . #xaab4 )
   ( #xaabe . #xaabf )
   ( #xaac1 . #xaac1 )
   ; Meetei Mayek Extensions
   ( #xaaeb . #xaaef )
   ( #xaaf5 . #xaaf5 )
   ; Meetei Mayek
   ( #xabe3 . #xabed )
   ; Alphabetic Presentation Forms
   ( #xfb1e . #xfb1e )
   ; Combining Half Marks
   ( #xfe20 . #xfe26 )
   ; Kharoshthi
   ( #x10a01 . #x10a0f )
   ( #x10a38 . #x10a3a )
   ; Brahmi
   ( #x11000 . #x11002 )
   ( #x11038 . #x11046 )
   ; Kaithi
   ( #x11080 . #x11082 )
   ( #x110b0 . #x110ba )
   ; Chakma
   ( #x11100 . #x11102 )
   ( #x11127 . #x11132 )
   ( #x11134 . #x11134 )
   ; Sharada
   ( #x11180 . #x11182 )
   ( #x111b3 . #x111c0 )
   ; Takri
   ( #x116ab . #x116b7 )
   ; Miao
   ( #x16f51 . #x16f7e )
   ; Musical Symbols
   ( #x1d165 . #x1d168 )
   ( #x1d16d . #x1d172 )
   ( #x1d17b . #x1d182 )
   ( #x1d185 . #x1d18b )
   ( #x1d1aa . #x1d1ad )
   ; Ancient Greek Musical Notation
   ( #x1d242 . #x1d244 )
   ;;; I hope, I did not make any mistake while typing this table
 ))


#(define (int-in-regions num reglist)
  (if (not (pair? reglist)) #f
   (if (not (pair? (car reglist))) #f
    (if (< num (caar reglist)) #f
     (if (<= num (cdar reglist)) #t
      (int-in-regions num (cdr reglist)))))))

#(define (wide-char-diacritic? codepoint)
 ; does this UNICODE codepoint refer to a diacrity modifyer?
  (int-in-regions codepoint unicode-diacritics))


#(define (wide-char-list->utf-8-glyphlist wcl)
 ; convert a list of UNICODE codepoint integers
 ; into a list of one character UTF-8 strings,
 ; but do not separate the combining diacritical modifyers
 ; (append them to the character strings)
  (let ((erg '()) (add-to-current #f))
   (for-each (lambda (u)
     (let ((us (if (eq? u 0) "\0" (ly:wide-char->utf-8 u))))
      (if add-to-current
       (set-car! erg (string-append us (car erg)))
       (set! erg (cons us erg)))
      (set! add-to-current (wide-char-diacritic? u)))) 
    (reverse wcl))
   erg))

#(define (wide-char-list->utf-8 wcl)
 ; Helper function to define utf-8 strings with a few special characters in it
  (let ((erg ""))
   (for-each (lambda (x)
     (if (string? x)
      (set! erg (string-append erg x))
      (if (integer? x)
       (if (eq? x 0)
        (set! erg (string-append erg "\0"))
        (set! erg (string-append erg (ly:wide-char->utf-8 x))))
       (if (list? x)
        (set! erg (string-append erg (wide-char-list->utf-8 x)))))))
    wcl)
   erg))

#(define (string->string-list strg)
  (wide-char-list->utf-8-glyphlist (utf-8-string->wide-char-list strg)))
  
#(define (string-list->string lst)
  (wide-char-list->utf-8 lst))
   
#(define (make-one-character-strings l1 l2)
    "
    l1 is supposed to be a list of strings.
    make-one-character-strings will return a new list l2, 
    build of the elements of l1.
    Every string of l2 a one character-string
    e.g '("12" "34") -> '("1" "2" "3" "4")
    "
  (if (null? l1)
     l2
     (make-one-character-strings 
       (cdr l1) (append l2 (string->string-list (car l1))))))
       
#(define (stack-chars stencil stils kern)
  (set! stencil (ly:stencil-combine-at-edge stencil X RIGHT (car stils) kern))
   (if (null? (cdr stils))
     stencil
     (stack-chars stencil (cdr stils) kern)))
         
#(define-markup-command (char-space layout props nmbr args)
  (number? markup-list?)
#:properties ((word-space 0.6) (word-space-left #f) (word-space-right #f))
  "
@cindex changing the space between single characters

Inserts @var{nmbr} to the space between every character of @var{args}. 
If @var{nmbr} is positive some additional space is created to the left and the 
right of @var{args}.
@code{word-space-left} and @code{word-space-right} may be used to determine the
space on the left or right side of @var{args}, @code{word-space} to determine it 
at both sides.

@lilypond[verbatim,quote]
\\markup \\override #'(line-width . 66) \\wordwrap {
  This text contains some \\bold \\char-space #-0.3 { compressed } parts and
  some parts which are \\bold \\char-space #1 { stretched. } If a part is 
  \\bold \\char-space #1 { stretched } some additional space will be inserted
  to the left and to the right. If you want to change the default use 
  the properties \\italic word-space, \\italic word-space-left and 
  \\italic word-space-right. 
  If a part is \\bold \\char-space #-0.3 { compressed } the space to the left 
  and to the right is not affected.
  Par example: 
  \\override #'(word-space . 2) \\bold \\char-space #1 { This little text }
  has more space on both sides.
  This will work with accented letters, german Umlaute etc: 
  \\bold \\char-space #1 { áéçäöü }
}
@end lilypond"
  (let* ((args-rev (remove (lambda (x) (string=? "" x)) args))
         (new-args (list-join args-rev " "))
         (argls (make-one-character-strings new-args '()))
         (pos-nmbr (max nmbr 0.0)) ; 'nmbr' limited to be not below 0.0
         (stils (map (lambda (x)(interpret-markup layout props x)) argls))
         (first-stil (if (eq? argls '()) point-stencil (car stils))))

 (ly:stencil-combine-at-edge  
   (ly:stencil-combine-at-edge
      (ly:make-stencil 
        "" 
        (cons 0 
              (abs (* pos-nmbr 
                      3 
                      (if (number? word-space-left) 
                          word-space-left 
                          word-space))))
        (cons 0 0))
      X RIGHT
      (if (<= (length argls) 1)
        first-stil
        (stack-chars first-stil (cdr stils) nmbr))
      0)
  X RIGHT
   (ly:make-stencil 
     "" 
     (cons 0 
           (abs (* pos-nmbr 
                   3 
                   (if (number? word-space-right) 
                       word-space-right 
                       word-space)))) 
     (cons 0 0))
   0)))
            
% testing functions, displaying in terminal
%%{
#(define strg "asdäöüøéàÆ")
     
#(let* ((l1 (utf-8-string->wide-char-list strg))
        (l2 (wide-char-list->utf-8-glyphlist l1))
        (new-strg (wide-char-list->utf-8 l1))
        (strg? (string? new-strg)))
  (newline)
  (newline)(display "\"The string\"__")(display strg)
  (newline)
  (display 
     "\"List of integers, \n  representing the UNICODE character codes\"__")
  (display l1)
  (newline)(display "\"List of one character UTF-8 strings\"__")(display l2)
  (newline)(display "\"Back to string\"__")(display new-strg)
  (newline)(display "\"string?\"__")(display strg?))
  
#(let* ((strg-lst (string->string-list strg))
        (new-strg (string-list->string strg-lst))
        (strg? (string? new-strg)))
     (newline)
     (newline)(display "\"The string\"__")(display strg)
     (newline)(display "\"The string-list\"__")(display strg-lst)
     (newline)(display "\"Back to string\"__")(display new-strg)
     (newline)(display "\"string?\"__")(display strg?)
     (newline))
     %}  
%------------ test
%{
\markup \column {
        "Tests for paranoiacs"
        \char-space #0.5 {  }
        xy
        \char-space #0.5 { "" }
        xy
        \override #'(word-space-left . 0)
        \char-space #0.5 { a "" a }
        xy
        \char-space #0.5 { "" "" }
        \override #'(word-space-left . 0)
        \char-space #0.5 { "" a "" }
        xy
        \override #'(word-space-left . 0)
        \char-space #0.5 { a }
        xy
        \override #'(word-space-left . 0)
        \char-space #3 { "Áasdäöüøéàæ" }
        \vspace #3
}
%}  
\markup
    \wordwrap {
      Der Zwischenraum
      \override #'(word-space-left . 2.5) \char-space #0.5 { links }
      und
      \override #'(word-space-right . 2.5) \char-space #0.5 { rechts }
      des gesperrten Textes kann individuell skaliert werden,
      aber natürlich auch
      \override #'(word-space . 2.5) \char-space #0.5 { beide }
      Seiten gemeinsam.
      Dies kann vor allem dann nötig werden, wenn
      \override #'(word-space-right . 0.0) \char-space #0.35 { unterschiedlich }
      \char-space #0.85 { gesperrte }
      Texte direkt aufeinander folgen.
      
      
      Natürlich ist es möglich Text auch zu
      \char-space #-0.25 { komprimieren. }
      Funktioniert auch mit Umlauten und Akzenten: 
      \bold \char-space #2 { áéçäöüÆ } 
      \bold \char-space #-0.25 { áéçäöüÆ }
    }

\header {
  composer = 
    \markup 
      \fill-line {
        \center-column {
          \fontsize #2 \char-space #4 { "CANTIONES SACRÆ" }
          \char-space #2 { "CANTIONES SACRÆ" }
          \char-space #0 { "CANTIONES SACRÆ" }
          \char-space #-0.5 { "CANTIONES SACRÆ" }
          \char-space #-1 { "CANTIONES SACRÆ" }
          \vspace #2
        }
      }
}



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

Reply via email to