2015-08-09 14:31 GMT+02:00 BB <[email protected]>:
> 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
[email protected]
https://lists.gnu.org/mailman/listinfo/lilypond-user