From: Marc Hohl Date: Fri, 10 Jul 2009 08:53:06 +0000 (+0200) Subject: New tablature features X-Git-Tag: release/2.13.4-1~206 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=8f4004f8cd8c0902c5a9409a3cd75c519f22ef47;p=lilypond.git New tablature features this patch includes: 1) tablature is now "numbers only" as default 2) dead notes and palm mute is supported 3) "tied to" fret numbers become invisible (or parenthesized after line breaks or in a second volta) 4) the slope of glissando lines points in the right direction 5) grace notes (even parenthesized) are represented by smaller fret numbers. --- diff --git a/input/regression/dead-notes.ly b/input/regression/dead-notes.ly new file mode 100644 index 0000000000..253fdd5bf3 --- /dev/null +++ b/input/regression/dead-notes.ly @@ -0,0 +1,26 @@ +\version "2.13.4" + +\header{ texidoc = "Muted notes (also called dead notes) are supported + within normal staves and tablature." + } + +deadnotes = \relative c,, { + e8. \deadNotesOn e16 \deadNotesOff g4 a b | + e8. \deadNote e16 g4 a b | + e,4. \deadNote { e8 e e } e4 | + < e, \deadNote b' e >8 < e \deadNote b' e > < e \deadNote b' e >4 < e \deadNote b' e >4 r + \bar "|." +} + +\context StaffGroup << + \context Staff << + \clef "bass_8" + \deadnotes + >> + \context TabStaff << + \set TabStaff.stringTunings = #bass-tuning + \deadnotes + >> +>> + + diff --git a/input/regression/modern-tab-clef-scaled.ly b/input/regression/modern-tab-clef-scaled.ly new file mode 100644 index 0000000000..12caf11139 --- /dev/null +++ b/input/regression/modern-tab-clef-scaled.ly @@ -0,0 +1,39 @@ +\version "2.13.4" + +\header{ texidoc = "The sans serif style tab clef is automatically adjusted to + different string spacings." + } + +guitar = \relative c { + c4 d e f + e4 d c2 +} + +\score { + << + \new Staff { + \clef "treble_8" + \guitar + } + \new TabStaff { + \clef "moderntab" + \set TabStaff.stringTunings = #guitar-tuning + \guitar + } + >> +} + +\score { + << + \new Staff { + \clef "treble_8" + \guitar + } + \new TabStaff { + \clef "moderntab" + \set TabStaff.stringTunings = #guitar-tuning + \override TabStaff.StaffSymbol #'staff-space = #1.0 % default value is 1.5 + \guitar + } + >> +} \ No newline at end of file diff --git a/input/regression/modern-tab-clef.ly b/input/regression/modern-tab-clef.ly new file mode 100644 index 0000000000..d95fb23bcb --- /dev/null +++ b/input/regression/modern-tab-clef.ly @@ -0,0 +1,44 @@ +\version "2.13.4" + +\header{ texidoc = "Sans serif style tab clefs are supported by @code{\\clef moderntab}. + This alternative clef supports four- to seven-stringed instruments + and is scaled automatically." + } + +bass = \relative c, { + c4 d e f + e4 d c2 +} + +guitar = \relative c { + c4 d e f + e4 d c2 +} + +\score { + << + \new Staff { + \clef "bass_8" + \bass + } + \new TabStaff { + \clef "moderntab" + \set TabStaff.stringTunings = #bass-four-string-tuning + \bass + } + >> +} + +\score { + << + \new Staff { + \clef "treble_8" + \guitar + } + \new TabStaff { + \clef "moderntab" + \set TabStaff.stringTunings = #guitar-seven-string-tuning + \guitar + } + >> +} \ No newline at end of file diff --git a/input/regression/palm-mute.ly b/input/regression/palm-mute.ly new file mode 100644 index 0000000000..33123f3f8e --- /dev/null +++ b/input/regression/palm-mute.ly @@ -0,0 +1,27 @@ +\version "2.13.4" + +\header{ texidoc = "The palm mute technique for stringed instruments + is supported by triangle-shaped note heads." + } + +palmmute = \relative c, { + \time 4/4 + e8^\markup { \musicglyph #"noteheads.u2do" = palm mute } + \palmMuteOn e e \palmMuteOff e e \palmMute e e e | + e8 \palmMute { e e e } e e e e | + \palmMuteOn < e b' e >8 e e e < e b' e >2 \palmMuteOff | + < \palmMute e b' e >8 \palmMute { e e e } < \palmMute e b' e >2 + \bar "|." +} + +\context StaffGroup << + \context Staff << + \clef "G_8" + \palmmute + >> + \context TabStaff << + \palmmute + >> +>> + + diff --git a/input/regression/tablature-full-notation.ly b/input/regression/tablature-full-notation.ly new file mode 100644 index 0000000000..80a48688be --- /dev/null +++ b/input/regression/tablature-full-notation.ly @@ -0,0 +1,36 @@ +\version "2.13.4" + +\header{ texidoc = "As default, tablature staves show only the fret numbers, because + in most situations, they are combined with normal staves. + When used without standard notation, @code{tabFullNotation} + can be used." + } + +tabstuff = { + \time 3/4 + c4^"test" d( e) + f4\f g a^\fermata + c8\<\( c16 c ~ c2\! + c'2.\) + \mark \default + R2. + r4 d4 r8 e + \times 3/4 { b4 c \glissando d\5 \glissando c } + c4. d-_( e\varcoda) + ->f g~ a\prall g\thumb e-. + \bar "|." +} + +\score { + << + \new Staff { \clef "G_8" \tabstuff } + \new TabStaff { \tabstuff } + >> +} + +\score { + \new TabStaff { + \tabFullNotation + \tabstuff + } +} diff --git a/input/regression/tablature-glissando.ly b/input/regression/tablature-glissando.ly new file mode 100644 index 0000000000..17db67a307 --- /dev/null +++ b/input/regression/tablature-glissando.ly @@ -0,0 +1,23 @@ +\version "2.13.4" + +\header{ texidoc = "Glissando lines in tablature have the right slope." + } + +\paper { ragged-right = ##f } % strech the staff to make glissando lines visible + +glissandotest = \relative c { + c4\5 \glissando d\5 \glissando e\5 f\5 | + c4\5 \glissando d\5 \glissando c2\5 | + c4\5 \glissando c'\4 c\4 \glissando c,\5 + \bar "|." +} + +\context StaffGroup << + \context Staff << + \clef "G_8" + \glissandotest + >> + \context TabStaff << + \glissandotest + >> +>> diff --git a/input/regression/tablature-grace-notes.ly b/input/regression/tablature-grace-notes.ly new file mode 100644 index 0000000000..5012ddd643 --- /dev/null +++ b/input/regression/tablature-grace-notes.ly @@ -0,0 +1,24 @@ +\version "2.13.4" + +\header{ texidoc = "Fret numbers belonging to grace notes are smaller." + } + +gracenotes = \relative c { + c4 d e f + \grace e8 c4 d e f + \grace \parenthesize e8 c4 d e f + \appoggiatura e8 c4 d e f + \acciaccatura e8 c4 d e f + \bar "|." +} + +\context StaffGroup << + \context Staff << + \clef "G_8" + \gracenotes + >> + \context TabStaff << + \gracenotes + >> +>> + diff --git a/input/regression/tablature-tie-behaviour.ly b/input/regression/tablature-tie-behaviour.ly new file mode 100644 index 0000000000..8760c9f204 --- /dev/null +++ b/input/regression/tablature-tie-behaviour.ly @@ -0,0 +1,31 @@ +\version "2.13.4" + +\header{ texidoc = "In tablature, notes that are tied to are invisible + except after a line break or within a second volta; + here, the fret number is displayed in parentheses." + } + +tietest = \relative c { + \override Voice.StringNumber #'transparent = ##t % remove circled string numbers + \repeat volta 2 { + f2 ~ f4 e + g8 g ~ g g ~ g g~ g g ~ + g1 + c1 ~ \break c2 ~ c + < c\3 e\2 g\1 >4 < c\3 e\2 g\1 > ~ < c\3 e\2 g\1 >\laissezVibrer r + c4. d8 e2 ~ + } + \alternative { { e2 r } { e2\repeatTie e2^\fermata } } + \bar "|." +} + +\context StaffGroup << + \context Staff << + \clef "G_8" + \tietest + >> + \context TabStaff << + \tietest + >> +>> + diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly index 9d19e92cdb..348d1a8c47 100644 --- a/ly/engraver-init.ly +++ b/ly/engraver-init.ly @@ -628,6 +628,7 @@ automatically when an output definition (a @code{\score} or (Voice Stem direction ,UP) (Voice Stem font-size -3) (Voice NoteHead font-size -3) + (Voice TabNoteHead font-size -4) (Voice Dots font-size -3) (Voice Stem length-fraction 0.8) (Voice Stem no-stem-extend #t) @@ -716,12 +717,39 @@ context." %% No accidental in tablature ! \remove "Accidental_engraver" - - \override Glissando #'extra-dy = #0.75 + %% remove stems, beams, dots and rests ... + \override Stem #'stencil = ##f + \override Beam #'stencil = ##f + \override Dots #'stencil = ##f + \override Rest #'stencil = ##f + \override MultiMeasureRest #'stencil = ##f + %% ... all kinds of ties/slurs + \override Tie #'stencil = ##f + \override RepeatTie #'stencil = ##f + \override LaissezVibrerTie #'stencil = ##f + \override Slur #'stencil = ##f + \override PhrasingSlur #'stencil = ##f + %% 'tied to' fret numbers become invisible or parenthesized, respectively) + \override Tie #'after-line-breaking = #tie::handle-tab-tie + \override RepeatTie #'after-line-breaking = #repeat-tie::parenthesize-tab-note-head + %% ... and all kinds of markups, spanners etc. + \override TupletBracket #'stencil = ##f + \override TupletNumber #'stencil = ##f + \override DynamicText #'transparent = ##t + \override DynamicTextSpanner #'stencil = ##f + \override TextSpanner #'stencil = ##f + \override Hairpin #'transparent = ##t + \override Script #'stencil = ##f + \override TextScript #'stencil = ##f + %% the direction for glissando lines will be automatically corrected + \override Glissando #'extra-dy = #glissando::calc-tab-extra-dy \override Glissando #'bound-details #'right = #`((attach-dir . ,LEFT) (padding . 0.3)) \override Glissando #'bound-details #'left = #`((attach-dir . ,RIGHT) (padding . 0.3)) + %% dead notes + \override TabNoteHead #'glyph-name = #tab-note-head::calc-glyph-name + \override TabNoteHead #'stencil = #tab-note-head::whiteout-if-style-set } \context { @@ -746,6 +774,14 @@ context." \remove "Accidental_engraver" \remove "Key_engraver" \remove "String_number_engraver" + %% the clef handler + \override Clef #'stencil = #clef::print-modern-tab-if-set + %% no time signature + \override TimeSignature #'stencil = ##f + %% better parentheses in a TabStaff + \override ParenthesesItem #'stencils = #parentheses-item::calc-tabstaff-parenthesis-stencils + %% no arpeggios + \override Arpeggio #'stencil = ##f %% Special "TAB" clef clefGlyph = #"clefs.tab" clefPosition = #0 diff --git a/ly/property-init.ly b/ly/property-init.ly index fd5c766ef7..f91c4b8d85 100644 --- a/ly/property-init.ly +++ b/ly/property-init.ly @@ -420,3 +420,84 @@ pointAndClickOff = #(define-music-function (parser location) () pointAndClickOn = #(define-music-function (parser location) () (ly:set-option 'point-and-click #t) (make-music 'SequentialMusic 'void #t)) + +palmMuteOn = { + \override NoteHead #'style = #'do +} + +palmMuteOff = { + \revert NoteHead #'style +} + +palmMute = +#(define-music-function (parser location note) (ly:music?) + ;; are we inside a <...>? + (if (eq? (ly:music-property note 'name) 'NoteEvent) + ;; yes -> add a tweak + (begin (set! (ly:music-property note 'tweaks) + (acons 'style 'do (ly:music-property note 'tweaks))) + note) + ;; no -> use predefined commands to switch to triangle-shaped note heads + #{ + \palmMuteOn + $note + \palmMuteOff + #})) + +deadNotesOn = { + \override TabNoteHead #'style = #'cross + \override NoteHead #'style = #'cross +} + +deadNotesOff = { + \revert TabNoteHead #'style + \revert NoteHead #'style +} + +deadNote = +#(define-music-function (parser location note) (ly:music?) + ;; are we inside a <...>? + (if (eq? (ly:music-property note 'name) 'NoteEvent) + ;; yes -> add a tweak + (begin (set! (ly:music-property note 'tweaks) + (acons 'style 'cross (ly:music-property note 'tweaks))) + note) + ;; no -> use predefined commmands for changing + ;; note head and tablature fret signs + #{ + \deadNotesOn + $note + \deadNotesOff + #})) + +tabFullNotation = { + % time signature + \revert TabStaff.TimeSignature #'stencil + % stems (the half note gets a double stem) + \override TabVoice.Stem #'stencil = #tabvoice::draw-double-stem-for-half-notes + % beams, dots + \revert TabVoice.Beam #'stencil + \revert TabVoice.Dots #'stencil + \revert TabVoice.Tie #'stencil + \revert TabVoice.Tie #'after-line-breaking + \revert TabVoice.RepeatTie #'stencil + \revert TabVoice.RepeatTie #'after-line-braking + \revert TabVoice.LaissezVibrerTie #'stencil + \revert TabVoice.Slur #'stencil + \revert PhrasingSlur #'stencil + % tuplet stuff + \revert TabVoice.TupletBracket #'stencil + \revert TabVoice.TupletNumber #'stencil + % dynamic signs + \revert DynamicText #'transparent + \revert DynamicTextSpanner #'stencil + \revert TabVoice.DynamicTextSpanner #'stencil + \revert TabVoice.Hairpin #'transparent + % rests + \revert TabVoice.Rest #'stencil + \revert TabVoice.MultiMeasureRest #'stencil + % markups etc. + \revert TabVoice.Script #'stencil + \revert TabVoice.TextScript #'stencil + \revert TabStaff.Arpeggio #'stencil +} diff --git a/scm/lily.scm b/scm/lily.scm index 7aa8c05c20..783679ca04 100644 --- a/scm/lily.scm +++ b/scm/lily.scm @@ -397,6 +397,7 @@ LilyPond safe mode. The syntax is the same as `define*-public'." "paper.scm" "backend-library.scm" "x11-color.scm" + "tablature.scm" ;; must be after everything has been defined "safe-lily.scm")) diff --git a/scm/music-functions.scm b/scm/music-functions.scm index c5e6f2da01..1372a15a52 100644 --- a/scm/music-functions.scm +++ b/scm/music-functions.scm @@ -384,6 +384,7 @@ i.e. this is not an override" ;; TODO: take this from voicedGraceSettings or similar. '((Voice Stem font-size -3) (Voice NoteHead font-size -3) + (Voice TabNoteHead font-size -4) (Voice Dots font-size -3) (Voice Stem length-fraction 0.8) (Voice Stem no-stem-extend #t) diff --git a/scm/output-lib.scm b/scm/output-lib.scm index f9b920f37d..db1181f740 100644 --- a/scm/output-lib.scm +++ b/scm/output-lib.scm @@ -89,22 +89,6 @@ )) -; default tunings for common string instruments -(define-public guitar-tuning '(4 -1 -5 -10 -15 -20)) -(define-public guitar-open-g-tuning '(2 -1 -5 -10 -17 -22)) -(define-public bass-tuning '(-17 -22 -27 -32)) -(define-public mandolin-tuning '(16 9 2 -5)) - -;; tunings for 5-string banjo -(define-public banjo-open-g-tuning '(2 -1 -5 -10 7)) -(define-public banjo-c-tuning '(2 -1 -5 -12 7)) -(define-public banjo-modal-tuning '(2 0 -5 -10 7)) -(define-public banjo-open-d-tuning '(2 -3 -6 -10 9)) -(define-public banjo-open-dm-tuning '(2 -3 -6 -10 9)) -;; convert 5-string banjo tuning to 4-string by removing the 5th string -(define-public (four-string-banjo tuning) - (reverse (cdr (reverse tuning)))) - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; note heads diff --git a/scm/parser-clef.scm b/scm/parser-clef.scm index fff8f1b83d..a6d178eaef 100644 --- a/scm/parser-clef.scm +++ b/scm/parser-clef.scm @@ -132,3 +132,10 @@ (sort (map car supported-clefs) string + +;; default tunings for common string instruments +;; guitar tunings +(define-public guitar-tuning '(4 -1 -5 -10 -15 -20)) +(define-public guitar-seven-string-tuning '(4 -1 -5 -10 -15 -20 -25)) +(define-public guitar-drop-d-tuning '(4 -1 -5 -10 -15 -22)) +(define-public guitar-open-g-tuning '(2 -1 -5 -10 -17 -22)) +;; bass tunings +(define-public bass-tuning '(-17 -22 -27 -32)) +(define-public bass-four-string-tuning '(-17 -22 -27 -32)) +(define-public bass-drop-d-tuning '(-17 -22 -27 -34)) +(define-public bass-five-string-tuning '(-17 -22 -27 -32 -37)) +(define-public bass-six-string-tuning '(-12 -17 -22 -27 -32 -37)) +;; mandolin +(define-public mandolin-tuning '(16 9 2 -5)) +;; tunings for 5-string banjo +(define-public banjo-open-g-tuning '(2 -1 -5 -10 7)) +(define-public banjo-c-tuning '(2 -1 -5 -12 7)) +(define-public banjo-modal-tuning '(2 0 -5 -10 7)) +(define-public banjo-open-d-tuning '(2 -3 -6 -10 9)) +(define-public banjo-open-dm-tuning '(2 -3 -6 -10 9)) +;; convert 5-string banjo tuning to 4-string by removing the 5th string +(define-public (four-string-banjo tuning) + (reverse (cdr (reverse tuning)))) + +;; for more control over glyph-name calculations, +;; we use a custom callback for tab noteheads +;; which will ignore 'style = 'do +(define-public (tab-note-head::calc-glyph-name grob) + (let ((style (ly:grob-property grob 'style))) + (case style + ((cross) "2cross")))) + +;; ensure we only call notehead callback when +;; 'style = 'cross +(define-public (tab-note-head::whiteout-if-style-set grob) + (let ((style (ly:grob-property grob 'style))) + (if (and (symbol? style) + (eq? style 'cross)) + (stencil-whiteout (ly:note-head::print grob)) + (ly:text-interface::print grob)))) + +;; definitions for the "moderntab" clef: +;; the "moderntab" clef will be added to the list of known clefs, +;; so it can be used as any other clef: \clef "moderntab" +(add-new-clef "moderntab" "markup.moderntab" 0 0 0) + +;; define sans serif-style tab-Clefs as a markup: +(define-builtin-markup-command (customTabClef layout props num-strings staff-space) + (integer? number?) + music + () + "Draw a tab clef sans-serif style." + (define (square x) (* x x)) + (let* ((scale-factor (/ staff-space 1.5)) + (font-size (- (* num-strings 1.5 scale-factor) 7)) + (base-skip (* (square (+ (* num-strings 0.195) 0.4)) scale-factor))) + + (interpret-markup layout props + (markup #:vcenter #:bold + #:override (cons 'font-family 'sans) + #:fontsize font-size + #:override (cons 'baseline-skip base-skip) + #:left-align #:center-column ("T" "A" "B"))))) + +;; this function decides which clef to take +(define-public (clef::print-modern-tab-if-set grob) + (let ((glyph (ly:grob-property grob 'glyph))) + ;; which clef is wanted? + (if (string=? glyph "markup.moderntab") + ;; if it is "moderntab", we'll draw it + (let* ((staff-symbol (ly:grob-object grob 'staff-symbol)) + (line-count (ly:grob-property staff-symbol 'line-count)) + (staff-space (ly:grob-property staff-symbol 'staff-space 1))) + (grob-interpret-markup grob (make-customTabClef-markup line-count staff-space))) + ;; otherwise, we simply use the default printing routine + (ly:clef::print grob)))) + +;; if stems are drawn, it is nice to have a double stem for +;; (dotted) half notes to distinguish them from quarter notes: +(define-public (tabvoice::draw-double-stem-for-half-notes grob) + (let ((stem (ly:stem::print grob))) + + ;; is the note a (dotted) half note? + (if (= 1 (ly:grob-property grob 'duration-log)) + ;; yes -> draw double stem + (ly:stencil-combine-at-edge stem X RIGHT stem 0.5) + ;; no -> draw simple stem + stem))) + +;; as default, the glissando line between fret numbers goes +;; upwards, here we have a function to correct this behavior: +(define-public (glissando::calc-tab-extra-dy grob) + (let* ((original (ly:grob-original grob)) + (left-bound (ly:spanner-bound original LEFT)) + (right-bound (ly:spanner-bound original RIGHT)) + (left-pitch (ly:event-property (event-cause left-bound) 'pitch)) + (right-pitch (ly:event-property (event-cause right-bound) 'pitch))) + + (if (< (ly:pitch-semitones right-pitch) (ly:pitch-semitones left-pitch)) + -0.75 + 0.75))) + +;; for ties in tablature, fret numbers that are tied to should be invisible, +;; except for 'tied to' numbers after a line break;; these will be +;; parenthesized (thanks to Neil for his solution): +(define-public (parenthesize-tab-note-head grob) + ;; Helper function to parenthesize tab noteheads, + ;; since we can't use ParenthesesItem at this stage + ;; This is basically the same as the C++ function + ;; in accidental.cc, converted to Scheme + (let* ((font (ly:grob-default-font grob)) + (open (stencil-whiteout + (ly:font-get-glyph font "accidentals.leftparen"))) + (close (stencil-whiteout + (ly:font-get-glyph font "accidentals.rightparen"))) + (me (ly:text-interface::print grob))) + (ly:stencil-combine-at-edge + (ly:stencil-combine-at-edge + me + X + LEFT + open) + X + RIGHT + close))) + +;; ParenthesesItem doesn't work very well for TabNoteHead, since +;; the parentheses are too small and clash with the staff-lines +;; Define a callback for the 'stencils property which will tweak +;; the parentheses' appearance for TabNoteHead +(define-public (parentheses-item::calc-tabstaff-parenthesis-stencils grob) + ;; the grob we want to parenthesize + (let ((victim (ly:grob-array-ref (ly:grob-object grob 'elements) 0))) + ;; check whether it's a notehead + (if (grob::has-interface victim 'note-head-interface) + (begin + ;; tweak appearance before retrieving + ;; list of stencils '(left-paren right-paren) + ;; get the font-size from victim (=TabNoteHead) to handle + ;; grace notes properly + (ly:grob-set-property! grob 'font-size + (ly:grob-property victim 'font-size)) + (ly:grob-set-property! grob 'padding 0) + ;; apply whiteout to each element of the list + (map stencil-whiteout + (parentheses-item::calc-parenthesis-stencils grob))) + (parentheses-item::calc-parenthesis-stencils grob)))) + +;; the handler for ties in tablature;; split ties yield in a parenthesized +;; fret number, otherwise the fret number will be invisible. +(define-public (tie::handle-tab-tie grob) + (let* ((original (ly:grob-original grob)) + (tied-tab-note-head (ly:spanner-bound grob RIGHT)) + (siblings (if (ly:grob? original) + (ly:spanner-broken-into original) '()))) + + (if (and (>= (length siblings) 2) + (eq? (car (last-pair siblings)) grob)) + ;; tie is split -> parenthesize + (ly:grob-set-property! tied-tab-note-head 'stencil + (lambda (grob) (parenthesize-tab-note-head grob))) + + ;; tie is not split -> make fret number invisible + (ly:grob-set-property! tied-tab-note-head 'transparent #t)))) + +;; repeat ties occur within alternatives in a repeat construct; +;; the correspondig fret numbers are shown in parentheses: +(define-public (repeat-tie::parenthesize-tab-note-head grob) + (let ((tied-tab-note-head (ly:grob-object grob 'note-head))) + + (ly:grob-set-property! tied-tab-note-head 'stencil + (lambda (grob) (parenthesize-tab-note-head grob))))) \ No newline at end of file