Re: [tablatures] harmonics in tablature

[ Thread Index | Date Index | More lilynet.net/tablatures Archives ]


Hello Patrick, hello tablature users,

I have now completed two functions for writing harmonics.
I invite you to test it and comment - I think they are quite useful, and
perhaps we can include them into the lilypond distribution.

The commands are

\harmonicByRatio #<ratio> <music>
where <ratio> is a fraction like 1/2, 1/3, 2/3 and so on. It marks the absolute place where you put your finger on the string, so 1/2 is the middle, 1/3 is the seventh fret,
2/3 the 19th fret (both sound equally) etc.

\harmonicByFret #<fret> <music>
where <fret> is the fret number. For higher naturals, fret numbers like 2.7 and 2.3
are supported.

<music> is any kind of musical expression. If you want to play several harmonics
on the same position, you can include them in { ... }. Harmonic chords are
possible, too. See harmonic.ly for some examples.



For this purpose, I had to write a new markup function, which cannot be included into the test file, so you have to insert the following lines into scm/tablature.scm (the place is irrelevant, but perhaps it is safe to append them at the end of the file):

(define-markup-command (customFretLabel
layout props font-series font-size fret-label)
 (symbol? number? string?)
 #:category music
 "Draw a custom tab fret label."

 (interpret-markup layout props
                   (markup #:vcenter
                           #:override (cons 'font-series font-series)
                           #:fontsize font-size
                           fret-label)))

After that, harmonic.ly should compile without errors.

Greetings,

Marc

\version "2.13.32"

#(define node-positions
  ;; for the node on m/n-th of the string length, we get the corresponding
  ;; (exact) fret position by calculating p=(-12/log 2)*log(1-(m/n));
  ;; since guitarists normally use the forth fret and not the 3.8th, here
  ;; are rounded values, ordered by
  ;; 1/2
  ;; 1/3 2/3
  ;; 1/4 2/4 3/4 etc.
  ;; The value for 2/4 is irrelevant in practical, bacause the string sounds
  ;; only one octave higher, not two, but since scheme normalizes the fractions
  ;; anyway, these values are simply placeholders for easier indexing.
  ;; According to the arithmetic sum, the position of m/n is at 1/2*(n-2)(n-1)+(m-1)
  ;; if we start counting from zero
  (vector 12
           7   19
           5   12    24
           4    9    16   28
           3    7    12   19    31
           2.7  5.8  9.7  14.7  21.7  33.7
           2.3  5    8    12    17    24    36
           2    4.4  7    10    14    19    26  38 ))

#(define partial-pitch
  (vector '(0 0 0)
          '(1 0 0)
          '(1 4 0)
          '(2 0 0)
          '(2 2 0)
          '(2 4 0)
          '(2 6 -1/2)
          '(3 0 0)
          '(3 1 0)))

#(define fret-partials
  '(("0" . 0)
    ("12" . 1)
    ("7" . 2)
    ("19" . 2)
    ("5" . 3)
    ("24" . 3)
    ("4" . 4)
    ("9" . 4)
    ("16" . 4)
    ("3" . 5)
    ("2.7" . 6)
    ("2.3" . 7)
    ("2" . 8)))

#(define (ratio->fret ratio)
  (let* ((nom (numerator ratio))
         (den (denominator ratio))
         (index (+ (* (- den 2)
                      (- den 1)
                      1/2)
                   nom -1)))
     (number->string (vector-ref node-positions index))))

#(define (ratio->pitch ratio)
  (let* ((partial (1- (denominator ratio)))
         (pitch (vector-ref partial-pitch partial)))

  (ly:make-pitch (first pitch)
                 (second pitch)
                 (third pitch))))

#(define (fret->pitch fret)
  (let* ((partial (assoc-get fret fret-partials 0))
         (pitch (vector-ref partial-pitch partial)))

  (ly:make-pitch (first pitch)
                 (second pitch)
                 (third pitch))))

#(define (calc-harmonic-pitch pitch music)
  (let ((es (ly:music-property music 'elements))
        (e (ly:music-property music 'element))
        (p (ly:music-property music 'pitch)))
    (cond
      ((pair? es)
       (ly:music-set-property! music 'elements
                               (map (lambda (x) (calc-harmonic-pitch pitch x)) es)))
      ((ly:music? e)
       (ly:music-set-property! music 'element (calc-harmonic-pitch pitch e)))
      ((ly:pitch? p)
       (begin
         (set! p (ly:pitch-transpose p pitch))
         (ly:music-set-property! music 'pitch p))))
    music))

% thanks to Neil for this function
#(define (make-harmonic mus)
  (let ((elts (ly:music-property mus 'elements))
        (elt (ly:music-property mus 'element)))
       (cond
	((pair? elts)
	 (map make-harmonic elts))
	((ly:music? elt)
	 (make-harmonic elt))
	((music-is-of-type? mus 'note-event)
	 (set! (ly:music-property mus 'articulations)
	       (append
		 (ly:music-property mus 'articulations)
		 (list (make-music 'HarmonicEvent))))))
       mus))

#(define-public ((tab-note-head::print-custom-fret-label fret) grob)
  (let ((font-series (ly:grob-property grob 'font-series))
        (font-size (ly:grob-property grob 'font-size)))

  (grob-interpret-markup grob (make-customFretLabel-markup
                                font-series 0 fret))))


harmonicByRatio = #(define-music-function (parser location ratio music) (number? ly:music?)
  (let ((pitch (ratio->pitch ratio))
        (fret (ratio->fret ratio)))
       (make-sequential-music
        (list
         #{
           \override TabNoteHead #'stencil = #(tab-note-head::print-custom-fret-label $fret)
         #}
         (make-harmonic
           (calc-harmonic-pitch pitch music))
         #{
            \revert TabNoteHead #'stencil
         #}))))


harmonicByFret = #(define-music-function (parser location fret music) (number? ly:music?)
  (let* ((fret (number->string fret))
         (pitch (fret->pitch fret)))
        (make-sequential-music
         (list
          #{
            \override TabNoteHead #'stencil = #(tab-note-head::print-custom-fret-label $fret)
          #}
          (make-harmonic
            (calc-harmonic-pitch pitch music))
          #{
            \revert TabNoteHead #'stencil
          #}))))



test = {
 e,4
 \harmonicByRatio #1/2  e,\6
 \harmonicByRatio #1/3  a,\5
 \harmonicByRatio #2/3  d,\4 |
 \harmonicByRatio #1/4 { g8\3 b\2 e'\1 b\2 < g b e >2 } |
 e,1 | % check whether tab note head is restored
 \harmonicByFret #12 e'4\1
 \ottava #1
 \harmonicByFret #7 e'4\1
 \harmonicByFret #5 e'4\1
 \ottava #2
 \harmonicByFret #4 < b\2 e'\1 >4 |
 \harmonicByFret #3 < g\3 b\2 e'\1 >4
 \harmonicByFret #2.7 < g\3 b\2 e'\1 >4
 \harmonicByFret #2.3 < g\3 b\2 e'\1 >4
 \harmonicByFret #2 < g\3 b\2 e'\1 >4 |
 \ottava #0
 e,1 | % check whether tab note head is restored
}

\paper {
  ragged-right = ##f
}

\score {
  <<
    \new Staff {
      \new Voice {
        \clef "treble_8"
        \override Voice.StringNumber #'transparent = ##t
        \test
      }
    }
    \new TabStaff {
      \new TabVoice {
        \test
      }
    }
  >>
}



Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/