--- /dev/null
+\version "2.11.57"
+
+\header {
+ texidoc = "Default flag styles: '(), 'mensural and 'no-flag.
+ Compare all three methods to print them (C++ default implementation,
+ Scheme implementation using the 'flag-style grob property and
+ setting the 'flag property explicitly to the desired Scheme function.
+ All three lines should be absolutely identical."
+}
+
+
+% test notes, which will be shown in different style:
+testnotes = { \autoBeamOff c'8 d'16 c'32 d'64 \acciaccatura {c'8} d'64 c''8 d''16 c''32 d''64 \acciaccatura {c''8} d''64 }
+
+{
+ \override Score.RehearsalMark #'self-alignment-X = #LEFT
+ \time 2/4
+ s2 \break
+
+ % Old settings: default, 'mensural, 'no-flag
+ \mark "Default flags (C++)"
+ \testnotes
+
+ \mark "Symbol: 'mensural (C++)"
+ \override Stem #'flag-style = #'mensural
+ \testnotes
+
+ \mark "Symbol: 'no-flag (C++)"
+ \override Stem #'flag-style = #'no-flag
+ \testnotes
+
+ \break
+
+ % The same, but with the Scheme implementation of default-flag
+ \override Stem #'flag = #default-flag
+ \revert Stem #'flag-style
+ \mark "Default flags (Scheme)"
+ \testnotes
+
+ \mark "Symbol: 'mensural (Scheme)"
+ \override Stem #'flag-style = #'mensural
+ \testnotes
+
+ \mark "Symbol: 'no-flag (Scheme)"
+ \override Stem #'flag-style = #'no-flag
+ \testnotes
+
+ \break
+
+ % New settings: no settings, normal-flag, mensural-flag, no-flag
+ \mark "Function: normal-flag"
+ \override Stem #'flag = #normal-flag
+ \testnotes
+
+ \mark "Function: mensural-flag"
+ \override Stem #'flag = #mensural-flag
+ \testnotes
+
+ \mark "Function: no-flag"
+ \override Stem #'flag = #no-flag
+ \testnotes
+}
--- /dev/null
+\version "2.11.57"
+
+\header {
+ texidoc = "The 'flag property of the Stem grob can be set to a custom
+scheme function to generate the glyph for the flag."
+}
+
+
+% test notes, which will be shown in different style:
+testnotes = { \autoBeamOff c'8 d'16 c'32 d'64 \acciaccatura {c'8} d'64 c''8 d''16 c''32 d''64 \acciaccatura {c''8} d''64 }
+
+#(define-public (weight-flag stem-grob)
+ (let* ((log (- (ly:grob-property stem-grob 'duration-log) 2))
+ (is-up (eqv? (ly:grob-property stem-grob 'direction) UP))
+ (yext (if is-up (cons (* log -0.8) 0) (cons 0 (* log 0.8))))
+ (flag-stencil (make-filled-box-stencil '(-0.4 . 0.4) yext))
+ (stroke-style (ly:grob-property stem-grob 'stroke-style))
+ (stroke-stencil (if (equal? stroke-style "grace") (make-line-stencil 0.2 -0.9 -0.4 0.9 -0.4) empty-stencil)))
+ (ly:stencil-add flag-stencil stroke-stencil)))
+
+
+% Create a flag stencil by looking up the glyph from the font
+#(define (inverted-flag stem-grob)
+ (let* ((dir (if (eqv? (ly:grob-property stem-grob 'direction) UP) "d" "u"))
+ (flag (retrieve-glyph-flag "" dir "" stem-grob))
+ (stroke-style (ly:grob-property stem-grob 'stroke-style))
+ (stencil (if (null? stroke-style) flag
+ (add-stroke-glyph flag stem-grob dir stroke-style ""))))
+ (ly:stencil-rotate stencil 180 -1 -1)))
+
+{
+ \override Score.RehearsalMark #'self-alignment-X = #LEFT
+ \time 2/4
+ \mark "Function: weight-flag (custom)"
+ \override Stem #'flag = #weight-flag
+ \testnotes
+
+ \mark "Function: inverted-flag (custom)"
+ \override Stem #'flag = #inverted-flag
+ \testnotes
+
+}
DECLARE_SCHEME_CALLBACK (pure_height, (SCM, SCM, SCM));
DECLARE_SCHEME_CALLBACK (height, (SCM));
DECLARE_SCHEME_CALLBACK (calc_cross_staff, (SCM));
+ DECLARE_SCHEME_CALLBACK (calc_flag, (SCM));
};
#endif
#include "grob.hh"
#include "staff-symbol-referencer.hh"
+#include "staff-symbol.hh"
#include "libc-extension.hh"
LY_DEFINE (ly_grob_staff_position, "ly:grob-staff-position",
else
return scm_from_double (pos);
}
+
+LY_DEFINE (ly_position_on_line_p, "ly:position-on-line?",
+ 2, 0, 0, (SCM sg, SCM spos),
+ "Return whether @var{pos} is on a line of the staff associated with the the grob @var{sg} (even on an extender line).")
+{
+ LY_ASSERT_SMOB (Grob, sg, 1);
+ LY_ASSERT_TYPE (scm_is_number, spos, 1);
+ Grob *g = unsmob_grob (sg);
+ Grob *st = Staff_symbol_referencer::get_staff_symbol (g);
+ int pos = scm_to_int (spos);
+ bool on_line = st ? Staff_symbol::on_line (g, pos) : false;
+ return scm_from_bool (on_line);
+}
return robust_scm2double (me->get_property ("stem-end-position"), 0);
}
-Stencil
-Stem::flag (Grob *me)
+MAKE_SCHEME_CALLBACK (Stem, calc_flag, 1);
+SCM
+Stem::calc_flag (SCM smob)
{
- int log = duration_log (me);
- if (log < 3
- || unsmob_grob (me->get_object ("beam")))
- return Stencil ();
+ Grob *me = unsmob_grob (smob);
- if (!is_normal_stem (me))
- return Stencil ();
-
+ int log = duration_log (me);
/*
TODO: maybe property stroke-style should take different values,
e.g. "" (i.e. no stroke), "single" and "double" (currently, it's
'() or "grace"). */
string flag_style;
- SCM flag_style_scm = me->get_property ("flag-style");
+ SCM flag_style_scm = me->get_property ("flag-style");
if (scm_is_symbol (flag_style_scm))
flag_style = ly_symbol2string (flag_style_scm);
if (flag_style == "no-flag")
- return Stencil ();
+ return Stencil ().smobbed_copy ();
bool adjust = true;
*/
{
if (adjust)
- {
- int p = (int) (rint (stem_end_position (me)));
- staffline_offs
- = Staff_symbol_referencer::on_line (me, p) ? "0" : "1";
- }
+ {
+ int p = (int) (rint (stem_end_position (me)));
+ staffline_offs
+ = Staff_symbol_referencer::on_line (me, p) ? "0" : "1";
+ }
else
- staffline_offs = "2";
- }
+ staffline_offs = "2";
+ }
else
staffline_offs = "";
{
string stroke_style = ly_scm2string (stroke_style_scm);
if (!stroke_style.empty ())
- {
- string font_char = to_string (dir) + stroke_style;
- Stencil stroke = fm->find_by_name ("flags." + font_char);
- if (stroke.is_empty ())
- me->warning (_f ("flag stroke `%s' not found", font_char));
- else
- flag.add_stencil (stroke);
- }
- }
+ {
+ string font_char = to_string (dir) + stroke_style;
+ Stencil stroke = fm->find_by_name ("flags." + font_char);
+ if (stroke.is_empty ())
+ me->warning (_f ("flag stroke `%s' not found", font_char));
+ else
+ flag.add_stencil (stroke);
+ }
+ }
+
+ return flag.smobbed_copy ();
+}
+
- return flag;
+Stencil
+Stem::flag (Grob *me)
+{
+ int log = duration_log (me);
+ if (log < 3
+ || unsmob_grob (me->get_object ("beam")))
+ return Stencil ();
+
+ if (!is_normal_stem (me))
+ return Stencil ();
+
+ // This get_property call already evaluates the scheme function with
+ // the grob passed as argument! Thus, we only have to check if a valid
+ // stencil is returned.
+ SCM flag_style_scm = me->get_property ("flag");
+ if (Stencil *flag = unsmob_stencil (flag_style_scm)) {
+ return *flag;
+ } else {
+ return Stencil ();
+ }
}
MAKE_SCHEME_CALLBACK (Stem, width, 1);
"details "
"direction "
"duration-log "
+ "flag "
"flag-style "
"french-beaming "
"length "
left side of the item and adding the @q{cdr} on the right side of the
item). In order to make a grob take up no horizontal space at all,
set this to @code{(+inf.0 . -inf.0)}.")
+ (flag ,ly:stencil? "A function returning the full flag stencil for
+the @code{Stem}, which is passed to the function as the only argument.
+The default ly:stem::calc-stencil function uses the @code{flag-style}
+property to determine the correct glyph for the
+flag. By providing your own function, you can create arbitrary flags.")
(flag-count ,number? "The number of tremolo beams.")
- (flag-style ,symbol? "A string determining what style of flag
-glyph is typeset on a @code{Stem}. Valid options include @code{()}
-and @code{mensural}. Additionally, @code{no-flag} switches off the
-flag.")
+ (flag-style ,symbol? "A symbol determining what style of flag
+glyph is typeset on a @code{Stem}. Valid options include @code{'()} for
+standard flags, @code{'mensural} and @code{'no-flag}, which switches off
+the flag.")
(font-encoding ,symbol? "The font encoding is the broadest
category for selecting a font. Options include: @code{fetaMusic},
@code{fetaNumber}, @code{TeX-text}, @code{TeX-math},
(length . ,ly:stem::calc-length)
(thickness . 1.3)
(cross-staff . ,ly:stem::calc-cross-staff)
+ (flag . ,ly:stem::calc-flag)
(details
. (
;; 3.5 (or 3 measured from note head) is standard length
--- /dev/null
+;;;; flag-styles.scm
+;;;;
+;;;; source file of the GNU LilyPOnd music typesetter
+;;;;
+
+(define-public (no-flag stem-grob)
+ "No flag: Simply return empty stencil"
+ empty-stencil)
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; Straight flags
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+;; ;; TODO
+;; (define-public (add-stroke-straight stencil dir stroke-style)
+;; stencil
+;; )
+;;
+;; ;; Create a stencil for a straight flag
+;; ;; flag-thickness, -spacing are given in staff spaces
+;; ;; *flag-length are given in black notehead widths
+;; ;; TODO
+;; (define-public (straight-flag flag-thickness flag-spacing
+;; upflag-angle upflag-length
+;; downflag-angle downflag-length)
+;; (lambda (stem-grob)
+;; (let* ((log (ly:grob-property stem-grob 'duration-log))
+;; (staff-space 1) ; TODO
+;; (black-notehead-width 1) ; TODO
+;; (stem-thickness 1) ; TODO: get rid of
+;; (half-stem-thickness (/ stem-thickness 2))
+;; (staff-space 1) ; TODO
+;; (up-length (+ (* upflag-length black-notehead-width) half-stem-thickness))
+;; (down-length (+ (* downflag-length black-notehead-width) half-stem-thickness))
+;; (thickness (* flag-thickness staff-space))
+;; (spacing (* flag-spacing staff-space)))
+;; empty-stencil
+;; )
+;; )
+;; )
+;;
+;; ;; Modern straight flags: angles are not so large as with the old style
+;; (define-public (modern-straight-flag stem-grob)
+;; ((straight-flag 0.55 0.9 -18 0.95 22 1.0) stem-grob))
+;;
+;; ;; Old-straight flags (Bach, etc.): quite large flag angles
+;; (define-public (old-straight-flag stem-grob)
+;; ((straight-flag 0.55 0.9 -45 0.95 45 1.0) stem-grob))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;; Flags created from feta glyphs (normal and mensural flags)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+; NOTE: By default, lilypond uses the C++ method Stem::calc-flag
+; (ly:stem::calc-flag is the corresponding Scheme interface) to generate the
+; flag stencil. The following functions are simply a reimplementation in
+; Scheme, so that one has that functionality available in Scheme, if one
+; wants to write a flag style, which modifies one of the standard flags
+; by some stencil operations.
+
+
+(define-public (add-stroke-glyph stencil stem-grob dir stroke-style flag-style)
+ "Load and add a stroke (represented by a glyph in the font) to the given
+ flag stencil"
+ (if (not (string? stroke-style))
+ stencil
+ ; Otherwise: look up the stroke glyph and combine it with the flag
+ (let* ((font-char (string-append "flags." flag-style dir stroke-style))
+ (alt-font-char (string-append "flags." dir stroke-style))
+ (font (ly:grob-default-font stem-grob))
+ (tmpstencil (ly:font-get-glyph font font-char))
+ (stroke-stencil (if (ly:stencil-empty? tmpstencil)
+ (ly:font-get-glyph font alt-font-char)
+ tmpstencil)))
+ (if (ly:stencil-empty? stroke-stencil)
+ (begin
+ (ly:warning (_ "flag stroke `~a' or `~a'not found") font-char alt-font-char)
+ stencil)
+ (ly:stencil-add stencil stroke-stencil)))))
+
+
+(define-public (retrieve-glyph-flag flag-style dir dir-modifier stem-grob)
+ "Load the correct flag glyph from the font"
+ (let* ((log (ly:grob-property stem-grob 'duration-log))
+ (font (ly:grob-default-font stem-grob))
+ (font-char (string-append "flags." flag-style dir dir-modifier (number->string log)))
+ (flag (ly:font-get-glyph font font-char)))
+ (if (ly:stencil-empty? flag)
+ (ly:warning "flag ~a not found" font-char))
+ flag))
+
+
+(define-public (create-glyph-flag flag-style dir-modifier stem-grob)
+ "Create a flag stencil by looking up the glyph from the font"
+ (let* ((dir (if (eqv? (ly:grob-property stem-grob 'direction) UP) "u" "d"))
+ (flag (retrieve-glyph-flag flag-style dir dir-modifier stem-grob))
+ (stroke-style (ly:grob-property stem-grob 'stroke-style)))
+ (if (null? stroke-style)
+ flag
+ (add-stroke-glyph flag stem-grob dir stroke-style flag-style))))
+
+
+
+(define-public (mensural-flag stem-grob)
+ "Mensural flags: Create the flag stencil by loading the glyph from the font.
+ Flags are always aligned with staff lines, so we need to check the end point
+ of the stem: For stems ending on staff lines, use different flags than for
+ notes between staff lines. The idea is that flags are always vertically
+ aligned with the staff lines, regardless of whether the note head is on a
+ staff line or between two staff lines. In other words, the inner end of
+ a flag always touches a staff line."
+
+ (let* ((adjust #t)
+ (stem-end (inexact->exact (round (ly:grob-property stem-grob 'stem-end-position))))
+ ; For some reason the stem-end is a real instead of an integer...
+ (dir-modifier (if (ly:position-on-line? stem-grob stem-end) "1" "0"))
+ (modifier (if adjust dir-modifier "2")))
+ (create-glyph-flag "mensural" modifier stem-grob)))
+
+
+
+(define-public ((glyph-flag flag-style) stem-grob)
+ "Simulates the default way of generating flags: look up glyphs
+ flags.style[ud][1234] from the feta font and use it for the flag stencil."
+ (create-glyph-flag flag-style "" stem-grob))
+
+
+
+(define-public (normal-flag stem-grob)
+ "Create a default flag"
+ (create-glyph-flag "" "" stem-grob))
+
+
+
+(define-public (default-flag stem-grob)
+ "Create a flag stencil for the stem. Its style will be derived from the
+ @code{'flag-style} Stem property. By default, @code{lilypond} uses a
+ C++ Function (which is slightly faster) to do exactly the same as this
+ function. However, if one wants to modify the default flags, this function
+ can be used to obtain the default flag stencil, which can then be modified
+ at will. The correct way to do this is:
+@example
+\\override Stem #'flag = #default-flag
+\\override Stem #'flag-style = #'mensural
+@end example
+"
+ (let* ((flag-style-symbol (ly:grob-property stem-grob 'flag-style))
+ (flag-style (if (symbol? flag-style-symbol)
+ (symbol->string flag-style-symbol)
+ "")))
+ (cond
+ ((equal? flag-style "") (normal-flag stem-grob))
+ ((equal? flag-style "mensural") (mensural-flag stem-grob))
+ ((equal? flag-style "no-flag") (no-flag stem-grob))
+ (else ((glyph-flag flag-style) stem-grob)))))
"font.scm"
"encoding.scm"
+ "flag-styles.scm"
"fret-diagrams.scm"
"harp-pedals.scm"
"predefined-fretboards.scm"
ly:number->string
ly:option-usage
ly:output-def-clone
+ ly:output-def-lookup
ly:output-def-scope
ly:output-description
ly:paper-book?
ly:paper-get-font
ly:paper-get-number
ly:paper-system?
- ly:output-def-lookup
ly:parser-parse-string
ly:pitch-alteration
ly:pitch-diff
ly:pitch-transpose
ly:pitch<?
ly:pitch?
+ ly:position-on-line?
ly:round-filled-box
ly:run-translator
ly:set-option