2015-08-09 14:31 GMT+02:00 BB <bb-543...@telecolumbus.net>:
> I found two possibilities to write arabic accidentals in the Notation
> reference.
> 2.10.1 Common notation for non-Western music
> \include "makam.ly"
> with English names (c d ...),
> and
> 2.10.2 Arabic music
> using the Italian names ( do re ...)
>
> Both hard to remember the different postfixes, but works anyway. I myself
> prefer the English name version.
>
> As a nonarabic Oud player I am interested in tabs with quarter tones. I was
> thinking about how to do this and found, that one might set a sign for half
> flat oder half sharp before the fret number in the tab. So I will be
> remembered to take care for that quarter tones. Well, fretless instruments
> do not have frets, but an equivalent finger set.
>
> Does anybody have such a solution or another one?
>
> Regards,
> BB


Hi,

attached you'll find my attempt for a such a tab.
It's based on `determine-frets' from translation-functions.scm

There's surely wide room for improvements and maybe the one or other glitch ...


Cheers,
  Harm
\version "2.19.24"

#(define-public
  (my-determine-frets context notes specified-info . rest)
  "Determine string numbers and frets for playing @var{notes}
as a chord, given specified information @var{specified-info}.
@var{specified-info} is a list with two list elements,
specified strings @code{defined-strings} and
specified fingerings @code{defined-fingers}.  Only a fingering of@tie{}0
will affect the fret selection, as it specifies an open string.
If @code{defined-strings} is @code{'()}, the context property
@code{defaultStrings} will be used as a list of defined strings.
Will look for predefined fretboards if @code{predefinedFretboardTable}
is not @code {#f}.  If @var{rest} is present, it contains the
@code{FretBoard} grob, and a fretboard will be
created.  Otherwise, a list of @code{(string fret finger)} lists will
be returned."

  ;;  helper functions

  (define (string-frets->placement-list string-frets string-count)
    "Convert @var{string-frets} to @code{fret-diagram-verbose}
dot placement entries."
    (let* ((placements (list->vector
                        (map (lambda (x) (list 'mute  x))
                             (iota string-count 1)))))

      (for-each (lambda (sf)
                  (let* ((string (car sf))
                         (fret (cadr sf))
                         (finger (caddr sf)))
                    (vector-set!
                     placements
                     (1- string)
                     (if (= 0 fret)
                         (list 'open string)
                         (if finger
                             (list 'place-fret string fret finger)
                             (list 'place-fret string fret))))))
                string-frets)
        (vector->list placements)))

  (define (placement-list->string-frets placement-list)
    "Convert @var{placement-list} to string-fret list."
    (map (lambda (x) (if (eq? (car x) 'place-fret)
                         (cdr x)
                         (list (cadr x) 0)))
         (filter (lambda (l) (or (eq? (car l) 'place-fret)
                                 (eq? (car l) 'open)))
                 placement-list)))

  (define (entry-count art-list)
    "Count the number of entries in a list of articulations."
    (length (filter (lambda (x) (not (null? x)))
                    art-list)))

  (define (string-number event)
    "Get the string-number from @var{event}.  Return @var{#f}
if no string-number is present."
    (let ((num (ly:event-property event 'string-number)))
      (and (integer? num) (positive? num) num)))

  (define (determine-frets-and-strings
           notes
           defined-strings
           defined-fingers
           minimum-fret
           maximum-stretch
           tuning)
    "Determine the frets and strings used to play the notes in
@var{notes}, given @var{defined-strings} and @var{defined-fingers}
along with @var{minimum-fret}, @var{maximum-stretch}, and
@var{tuning}.  Returns a list of @code{(string fret finger) lists."


    (define restrain-open-strings (ly:context-property context
                                                       'restrainOpenStrings
                                                       #f))
    (define specified-frets '())
    (define free-strings (iota (length tuning) 1))

    (define (calc-fret pitch string tuning)
      "Calculate the fret to play @var{pitch} on @var{string} with
@var{tuning}."
      (* 2  (- (ly:pitch-tones pitch) (ly:pitch-tones (list-ref tuning (1- string))))))

    (define (note-pitch note)
      "Get the pitch (in semitones) from @var{note}."
      (ly:event-property note 'pitch))

    (define (note-finger ev)
      "Get the fingering from @var{ev}.  Return @var{#f}
if no fingering is present."
      (let* ((articulations (ly:event-property ev 'articulations))
             (finger-found #f))
        (for-each (lambda (art)
                    (let* ((num (ly:event-property art 'digit)))

                      (if (and (ly:in-event-class? art 'fingering-event)
                               (number? num)
                               (> num 0))
                          (set! finger-found num))))
                  articulations)
        finger-found))

    (define (delete-free-string string)
      (if (number? string)
          (set! free-strings
                (delete string free-strings))))

    (define (close-enough fret)
      "Decide if @var{fret} is acceptable, given the already used frets."
      (every (lambda (specced-fret)
               (or (zero? specced-fret)
                   (zero? fret)
                   (>= maximum-stretch (abs (- fret specced-fret)))))
             specified-frets))

    (define (string-qualifies string pitch)
      "Can @var{pitch} be played on @var{string}, given already placed
notes?"
      (let* ((fret (calc-fret pitch string tuning)))
        (and (or (and (not restrain-open-strings)
                      (zero? fret))
                 (>= fret minimum-fret))
             (integer? (truncate fret))
             (close-enough fret))))

    (define (open-string string pitch)
      "Is @var{pitch} and open-string note on @var{string}, given
the current tuning?"
      (let* ((fret (calc-fret pitch string tuning)))
        (zero? fret)))

    (define (set-fret! pitch-entry string finger)
      (let* ((this-fret (calc-fret (car pitch-entry)
                                   string
                                   tuning)))
        (if (< this-fret 0)
            (ly:warning (_ "Negative fret for pitch ~a on string ~a")
                        (car pitch-entry) string)
            (if (not (integer? (truncate this-fret)))
                (ly:warning (_ "Missing fret for pitch ~a on string ~a")
                            (car pitch-entry) string)))
        (delete-free-string string)
        (set! specified-frets (cons this-fret specified-frets))
        (list-set! string-fret-fingers
                   (cdr pitch-entry)
                   (list string this-fret finger))))

    (define (kill-note! string-fret-fingers note-index)
      (list-set! string-fret-fingers note-index (list #f #t)))

    (define string-fret-fingers
      (map (lambda (string finger)
             (if (null? finger)
                 (list string #f)
                 (list string #f finger)))
           defined-strings defined-fingers))

    ;;; body of determine-frets-and-strings
    (let* ((pitches (map note-pitch notes))
           (pitch-alist (map cons pitches (iota (length pitches)))))

      ;; handle notes with strings assigned and fingering of 0
      (for-each
       (lambda (pitch-entry string-fret-finger)
         (let* ((string (list-ref string-fret-finger 0))
                (finger (if (= (length string-fret-finger) 3)
                            (list-ref string-fret-finger 2)
                            '()))
                (pitch (car pitch-entry))
                (digit (if (null? finger)
                           #f
                           finger)))
           (if (or (not (null? string))
                   (eqv? digit 0))
               (if (eqv? digit 0)
                   ;; here we handle fingers of 0 -- open strings
                   (let ((fit-string
                          (find (lambda (string)
                                  (open-string string pitch))
                                free-strings)))
                     (if fit-string
                         (set-fret! pitch-entry fit-string #f)
                         (ly:warning (_ "No open string for pitch ~a")
                                     pitch)))
                   ;; here we handle assigned strings
                   (let ((this-fret
                          (calc-fret pitch string tuning))
                         (handle-negative
                          (ly:context-property context
                                               'handleNegativeFrets
                                               'recalculate)))
                     (cond ((or (and (>= this-fret 0) (integer? this-fret))
                                (eq? handle-negative 'include))
                            (set-fret! pitch-entry string finger))
                           ((eq? handle-negative 'recalculate)
                            (begin
                              (ly:warning
                               (_ "Requested string for pitch requires negative fret: string ~a pitch ~a")
                               string
                               pitch)
                              (ly:warning (_ "Ignoring string request and recalculating."))
                              (list-set! string-fret-fingers
                                         (cdr pitch-entry)
                                         (if (null? finger)
                                             (list '() #f)
                                             (list '() #f finger)))))
                           ((eq? handle-negative 'ignore)
                            (begin
                              (ly:warning
                               (_ "Requested string for pitch requires negative fret: string ~a pitch ~a")
                               string
                               pitch)
                              (ly:warning (_ "Ignoring note in tablature."))
                              (kill-note! string-fret-fingers
                                          (cdr pitch-entry))))))))))
       pitch-alist string-fret-fingers)
      ;; handle notes without strings assigned -- sorted by pitch, so
      ;; we need to use the alist to have the note number available
      (for-each
       (lambda (pitch-entry)
         (let* ((string-fret-finger (list-ref string-fret-fingers
                                              (cdr pitch-entry)))
                (string (list-ref string-fret-finger 0))
                (finger (if (= (length string-fret-finger) 3)
                            (list-ref string-fret-finger 2)
                            '()))
                (pitch (car pitch-entry))
                (fit-string
                 (find (lambda (string)
                         (string-qualifies string pitch))
                       free-strings)))
           (if (not (list-ref string-fret-finger 1))
               (if fit-string
                   (set-fret! pitch-entry fit-string finger)
                   (begin
                     (ly:event-warning
                      (list-ref notes (cdr pitch-entry))
                      (_ "No string for pitch ~a (given frets ~a)")
                      pitch
                      specified-frets)
                     (kill-note! string-fret-fingers
                                 (cdr pitch-entry)))))))
       (sort pitch-alist (lambda (pitch-entry-a pitch-entry-b)
                           (ly:pitch<? (car pitch-entry-b)
                                       (car pitch-entry-a)))))
      string-fret-fingers)) ;; end of determine-frets-and-strings

  (define (get-predefined-fretboard predefined-fret-table tuning pitches)
    "Search through @var{predefined-fret-table} looking for a predefined
fretboard with a key of @var{(tuning . pitches)}.  The search will check
both up and down an octave in order to accomodate transposition of the
chords.  Returns a placement-list."

    (define (get-fretboard key)
      (let ((hash-handle
             (hash-get-handle predefined-fret-table key)))
        (if hash-handle
            (cdr hash-handle)  ; return table entry
            '())))

    ;; body of get-predefined-fretboard
    (let ((test-fretboard (get-fretboard (cons tuning pitches))))
      (if (not (null? test-fretboard))
          test-fretboard
          (let ((test-fretboard
                 (get-fretboard
                  (cons tuning (map (lambda (x) (shift-octave x 1)) pitches)))))
            (if (not (null? test-fretboard))
                test-fretboard
                (get-fretboard
                 (cons tuning (map (lambda (x) (shift-octave x -1))
                                   pitches))))))))

  ;; body of determine-frets
  (let* ((predefined-fret-table
          (ly:context-property context 'predefinedDiagramTable))
         (tunings (ly:context-property context 'stringTunings))
         (string-count (length tunings))
         (grob (if (null? rest) '() (car rest)))
         (pitches (map (lambda (x) (ly:event-property x 'pitch)) notes))
         (defined-strings (map (lambda (x)
                                 (if (null? x)
                                     x
                                     (or (string-number x) '())))
                               (car specified-info)))
         (defined-fingers (map (lambda (x)
                                 (if (null? x)
                                     x
                                     (ly:event-property x 'digit)))
                               (cadr specified-info)))
         (default-strings (ly:context-property context 'defaultStrings '()))
         (strings-used (if (and (zero? (entry-count defined-strings))
                                (not (zero? (entry-count default-strings))))
                           default-strings
                           defined-strings))
         (predefined-fretboard
          (if predefined-fret-table
              (get-predefined-fretboard
               predefined-fret-table
               tunings
               pitches)
              '())))
    (if (null? predefined-fretboard)
        (let ((string-frets
               (determine-frets-and-strings
                notes
                strings-used
                defined-fingers
                (ly:context-property context 'minimumFret 0)
                (ly:context-property context 'maximumFretStretch 4)
                tunings)))
          (if (null? grob)
              string-frets
              (create-fretboard
               context grob (string-frets->placement-list
                             (filter (lambda (entry)
                                       (car entry))
                                     string-frets)
                             string-count))))
        (if (null? grob)
            (placement-list->string-frets predefined-fretboard)
            (create-fretboard context grob predefined-fretboard)))))


#(define (integer-and-fraction nmbr)
  "Return a list with an integer and a fraction build from an exact number
Example: 47/7 -> (6 5/7) "
  (let*  ((i (inexact->exact (truncate nmbr)))
          (rest (string->number (format #f "~a~a" "#e" (- nmbr i)))))
          ;; return a string
          ;(format #f "~a~a"
          ;  i
          ;  (if (= rest 0) 
          ;      ""
          ;      (string-append " " (number->string rest))))
          ;; return a list
          (list i rest)
                ))
                
%% Better to do formatting not in `my-determine-frets'
#(define my-format-tab-note-head
  (lambda (grob)
    (let* ((txt (ly:grob-property grob 'text))
           (nmbr (if (not (null? txt)) (car (last-pair txt)) '())))
     (if (string? nmbr)
         (let* ((val (integer-and-fraction (string->number nmbr)))
                (fret
                  (if (and (zero? (car val)) (not (zero? (cadr val))))
                      ""
                      (number->string (car val))))
                (frac
                  (cond ((zero? (cadr val)) "")
                        ((string-null? fret) (number->string (cadr val)))
                        (else
                          (markup 
                            #:fontsize -2.5 
                            (number->string (cadr val)))))))
           (ly:grob-set-property! grob 'text
             #{ \markup \concat \vcenter { #fret #frac } #}))
         txt))))
         
\layout {
  \context {
    \Score
    noteToFretFunction = #my-determine-frets
  }
  \context {
    \TabStaff
    \override TabNoteHead.before-line-breaking = #my-format-tab-note-head
  }
}

%%%% Only compile with one of the below examples. Don't uncomment two of them
%%%% \language "english", "makam.ly", \include "arabic.ly" may disturb 
%%%%  each other
%%%%%%%%%%%%%%%%%%%%%%%%
%% ENGLISH NOTE NAMES
%%%%%%%%%%%%%%%%%%%%%%%%

%%{
\language "english"
m =
\relative {
  \cadenzaOn
  <>^"E"
  e, eqs es etqs ess
  <>^"F" \bar "||"
  ff fqf f fqs fs ftqs fss
  <>^"G" \bar "||"
  gff gtqf gf gqf g gqs gs gtqs gss 
  <>^"A" \bar "||"
  aff atqf af aqf a aqs as atqs ass 
  <>^"B" \bar "||"
  bff btqf bf bqf b bqs bs btqs bss 
  <>^"C" \bar "||"
  cff ctqf cf cqf c cqs cs ctqs css 
  <>^"D" \bar "||"
  dff dtqf df dqf d dqs ds dtqs dss 
  
  <>^"E" \bar "||"
  eff etqf ef eqf e eqs es etqs ess
  <>^"F" \bar "||"
  fff ftqf ff fqf f fqs fs ftqs fss
  <>^"G" \bar "||"
  gff gtqf gf gqf g gqs gs gtqs gss 
  <>^"A" \bar "||"
  aff atqf af aqf a aqs as atqs ass 
  <>^"B" \bar "||"
  bff btqf bf bqf b bqs bs btqs bss 
  <>^"C" \bar "||"
  cff ctqf cf cqf c cqs cs ctqs css 
  <>^"D" \bar "||"
  dff dtqf df dqf d dqs ds dtqs dss 
  <>^"E" \bar "||"
  eff etqf ef eqf e eqs es etqs ess
  <>^"F" \bar "||"
  fff ftqf ff fqf f fqs fs ftqs fss
  <>^"G" \bar "||"
  gff gtqf gf gqf g gqs gs gtqs gss 
  <>^"A" \bar "||"
  aff atqf af aqf a aqs as atqs ass
  \bar "||"
  <>^"B" \bar "||"
  bff btqf bf bqf b bqs bs btqs bss 
  <>^"C" \bar "||"
  cff ctqf cf cqf c cqs cs ctqs css 
  <>^"D" \bar "||"
  dff dtqf df dqf d dqs ds dtqs dss 
  \bar "||"
}
%}

%%%%%%%%%%%%%%%%%%%%%%%%
%% "makam.ly"
%%%%%%%%%%%%%%%%%%%%%%%%

%{
\include "makam.ly"
  
m = \relative {
  \cadenzaOn
  c d e f g a b 
  \bar "||"
  cc, dc ec fc gc ac bc 
  \bar "||"
  cb, db eb fb gb ab bb 
  \bar "||"
  ck, dk ek fk gk ak bk 
  \bar "||"
  cbm, dbm ebm fbm gbm abm bbm 
  \bar "||"
  cfc, dfc efc ffc gfc afc bfc 
  \bar "||"
  cfb, dfb efb ffb gfb afb bfb 
  \bar "||"
  cfk, dfk efk ffk gfk afk bfk 
  \bar "||"
  cfi, dfi efi ffi gfi afi bfi 
  \bar "||"
  cfu, dfu efu ffu gfu afu bfu 
  \bar "||"
  cfbm, dfbm efbm ffbm gfbm afbm bfbm
  \bar "||"
}
%}

%%%%%%%%%%%%%%%%%%%%%%%%
%% "arabic.ly"
%%%%%%%%%%%%%%%%%%%%%%%%

%{
\include "arabic.ly"
 
m =
\relative {
  \cadenzaOn
  dobb dobsb dob dosb do dosd dod dodsd dodd  
  \bar "||"
  rebb rebsb reb resb re resd red redsd redd  
  \bar "||"
  mibb mibsb mib misb mi misd mid midsd midd  
  \bar "||"
  fabb fabsb fab fasb fa fasd fad fadsd fadd  
  \bar "||"
  solbb solbsb solb solsb sol solsd sold soldsd soldd  
  \bar "||"
  labb labsb lab lasb la lasd lad ladsd ladd 
  \bar "||" 
  sibb sibsb sib sisb si sisd sid sidsd sidd 
  \bar "||"
}
%}

<<
\new Staff << \clef "G_8" \m >>
\new TabStaff << \m >>
>>

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

Reply via email to