+2003-05-17 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+ * input/regression/markup-note.ly: new file
+
+ * input/regression/metronome-marking.ly: new file
+
+ * lily/metronome-engraver.cc: new file. Print \tempo markings.
+
+ * scm/new-markup.scm (note-markup): make a note glyph, useful for
+ metronome marks.
+
2003-05-17 Jan Nieuwenhuizen <janneke@gnu.org>
* Documentation/user/GNUmakefile: Compatibility fix for new
@end example
For example,
-
-@ignore
-@example[relative 0]
+@example
\time 2/4
c2. c8 d4 e f g a b c8 c2 b4 a g16 f4 e d c8. c2
@end example
-@end ignore
@lilypond[noindent]
\score{
--- /dev/null
+\header {
+
+ texidoc = "The note markup function is used to make metronome
+ markings. It works for a variety of flag dot and duration settings."
+}
+\version "1.7.18"
+
+\score { \notes { c4^\markup {
+ \note #0 #0 #1
+ \note #1 #0 #1
+ \note #2 #0 #1
+ \note #3 #0 #1
+ \note #4 #0 #1
+ \note #5 #0 #1
+ \note #6 #0 #1
+
+ \note #0 #0 #-1
+ \note #1 #0 #-1
+ \note #2 #0 #-1
+ \note #3 #0 #-1
+ \note #4 #0 #-1
+ \note #5 #0 #-1
+ \note #6 #0 #-1
+
+ \note #0 #1 #-1
+ \note #1 #1 #-1
+ \note #2 #1 #-1
+ \note #3 #1 #-1
+ \note #4 #1 #-1
+ \note #5 #1 #-1
+ \note #6 #1 #-1
+
+ \note #0 #1 #1
+ \note #1 #1 #1
+ \note #2 #1 #1
+ \note #3 #1 #1
+ \note #4 #1 #1
+ \note #5 #1 #1
+ \note #6 #1 #1
+
+}
+
+} }
--- /dev/null
+
+\header {
+
+ texidoc = "@code{\tempo} directives are printed as metronome markings.
+
+THe marking is left aligned with the time signature, if there is one.
+"
+
+ }
+
+\version "1.7.18"
+
+\score { \notes \relative c'' { \tempo \breve = 100 c1 c1 \tempo 8.. = 50 c1 }
+\paper { raggedright = ##t }
+
+ }
+
return MARKUP_HEAD_SCM0_MARKUP1;
else if (tag == ly_symbol2scm ("scheme0-scheme1-markup2"))
return MARKUP_HEAD_SCM0_SCM1_MARKUP2;
+ else if (tag == ly_symbol2scm ("scheme0-scheme1-scheme2"))
+ return MARKUP_HEAD_SCM0_SCM1_SCM2;
else {
+ programming_error ("No parser tag defined for this signature. Abort");
ly_display_scm (s);
assert(false);
}
--- /dev/null
+/*
+ mark-engraver.cc -- implement Metronome_mark_engraver
+
+ source file of the GNU LilyPond music typesetter
+
+ (c) 1998--2003 Jan Nieuwenhuizen <janneke@gnu.org>
+*/
+
+#include <ctype.h>
+
+#include "bar-line.hh"
+#include "time-signature.hh"
+#include "engraver.hh"
+#include "engraver-group-engraver.hh"
+#include "item.hh"
+
+/**
+ put stuff over or next to bars. Examples: bar numbers, marginal notes,
+ rehearsal marks.
+ */
+class Metronome_mark_engraver : public Engraver
+{
+public:
+ TRANSLATOR_DECLARATIONS(Metronome_mark_engraver);
+protected:
+ Item* text_;
+ Grob * bar_line_;
+
+protected:
+ virtual void stop_translation_timestep ();
+ virtual void acknowledge_grob (Grob_info);
+ void create_items (Music*);
+ virtual bool try_music (Music *req);
+ virtual void start_translation_timestep ();
+ virtual void process_music ();
+
+private:
+ Music * mark_req_;
+};
+
+Metronome_mark_engraver::Metronome_mark_engraver ()
+{
+ text_ =0;
+ mark_req_ = 0;
+}
+
+void
+Metronome_mark_engraver::acknowledge_grob (Grob_info inf)
+{
+ if (Bar_line::has_interface (inf.grob_))
+ {
+ bar_line_ = inf.grob_;
+ }
+ else if (text_ && Time_signature::has_interface (inf.grob_))
+ {
+ text_->set_parent (inf.grob_, X_AXIS);
+ }
+}
+
+void
+Metronome_mark_engraver::stop_translation_timestep ()
+{
+ if (text_)
+ {
+ if (bar_line_ && !text_->get_parent (X_AXIS))
+ text_->set_parent (bar_line_, X_AXIS);
+
+ text_->set_grob_property ("side-support-elements" , get_property ("stavesFound"));
+ typeset_grob (text_);
+ text_ =0;
+ }
+}
+
+
+void
+Metronome_mark_engraver::create_items (Music *rq)
+{
+ if (text_)
+ return;
+
+ SCM s = get_property ("MetronomeMark");
+ text_ = new Item (s);
+
+ announce_grob(text_, rq->self_scm());
+}
+
+void
+Metronome_mark_engraver::start_translation_timestep ()
+{
+ mark_req_ = 0;
+}
+
+bool
+Metronome_mark_engraver::try_music (Music* r)
+{
+ mark_req_ = r;
+ return true;
+}
+
+void
+Metronome_mark_engraver::process_music ()
+{
+ if (mark_req_)
+ {
+ create_items (mark_req_);
+
+ SCM proc = get_property ("metronomeMarkFormatter");
+ SCM result= scm_call_2 (proc, mark_req_->self_scm (),
+ daddy_trans_->self_scm());
+
+ text_->set_grob_property ("text", result);
+ }
+}
+
+ENTER_DESCRIPTION(Metronome_mark_engraver,
+/* descr */ "Engrave metro nome marking. This delegates the real work to the function in the metronomeMarkFormatter property",
+/* creats*/ "MetronomeMark",
+/* accepts */ "metronome-change-event",
+/* acks */ "time-signature-interface bar-line-interface",
+/* reads */ "stavesFound metronomeMarkFormatter",
+/* write */ "");
%token <scm> MARKUP_HEAD_SCM0
%token <scm> MARKUP_HEAD_SCM0_MARKUP1
%token <scm> MARKUP_HEAD_SCM0_SCM1
+%token <scm> MARKUP_HEAD_SCM0_SCM1_SCM2
%token <scm> MARKUP_HEAD_SCM0_SCM1_MARKUP2
%token <scm> MARKUP_IDENTIFIER MARKUP_HEAD_LIST0
tempo_event:
TEMPO steno_duration '=' bare_unsigned {
- $$ = MY_MAKE_MUSIC("TempoEvent");
+ $$ = MY_MAKE_MUSIC("MetronomeChangeEvent");
$$->set_mus_property ("tempo-unit", $2);
$$->set_mus_property ("metronome-count", gh_int2scm ( $4));
}
THIS->lexer_->pop_state ();
}
;
-
+
+
+/*
+This should be done more dynamically if possible.
+*/
markup:
STRING {
$$ = make_simple_markup ($1);
| MARKUP_HEAD_SCM0_SCM1_MARKUP2 embedded_scm embedded_scm markup {
$$ = scm_list_n ($1, $2, $3, $4, SCM_UNDEFINED);
}
+ | MARKUP_HEAD_SCM0_SCM1_SCM2 embedded_scm embedded_scm embedded_scm {
+ $$ = scm_list_n ($1, $2, $3, $4, SCM_UNDEFINED);
+ }
| MARKUP_IDENTIFIER {
$$ = $1;
}
ENTER_DESCRIPTION (Tempo_performer, "","",
- "tempo-event",
+ "metronome-change-event",
"","","" );
\consists "Output_property_engraver"
\consists "System_start_delimiter_engraver"
\consists "Mark_engraver"
+ \consists "Metronome_mark_engraver"
\consists "Break_align_engraver"
\consists "Spacing_engraver"
\consists "Vertical_align_engraver"
%%
bassFigureFormatFunction = #make-bass-figure-markup
-
+ metronomeMarkFormatter = #make-metronome-markup
\grobdescriptions #all-grob-descriptions
}
(RehearsalMark
. (
- (molecule-callback . ,Text_item::brew_molecule)
+ (molecule-callback . ,brew-new-markup-molecule)
(X-offset-callbacks . (,Self_alignment_interface::aligned_on_self))
(Y-offset-callbacks . (,Side_position_interface::aligned_side))
(self-alignment-X . 0)
-
+ (break-align-symbol . time-signature)
(direction . 1)
(breakable . #t)
(font-family . roman)
(padding . 0.8)
(meta . ((interfaces . (text-interface side-position-interface font-interface mark-interface self-alignment-interface item-interface ))))
))
-
+ (MetronomeMark
+ . (
+ (molecule-callback . ,brew-new-markup-molecule)
+ (Y-offset-callbacks . (,Side_position_interface::aligned_side))
+ (direction . 1)
+ (breakable . #t)
+ (font-family . roman)
+ (break-visibility . ,end-of-line-invisible)
+ (padding . 0.8)
+ (meta . ((interfaces . (text-interface side-position-interface font-interface metronome-mark-interface item-interface))))
+ ))
(MeasureGrouping
. (
(Y-offset-callbacks . (,Side_position_interface::out_of_staff
'(
))
+(ly:add-interface
+ 'metronome-mark-interface
+ "a rehearsal mark"
+ '(
+ ))
+
;;; todo: this is not typesetting info. Move to interpretation.
(ly:add-interface
'tablature-interface
)
+(define-public (range x y)
+ "Produce a list of integers starting at Y with X elements."
+ (if (<= x 0)
+ '()
+ (cons y (range (- x 1) (+ y 1)))
+
+ )
+ )
+
+(define-public (interval-length x)
+ "Length of the number-pair X, when an interval"
+ (max 0 (- (cdr x) (car x)))
+ )
+
+
(define (other-axis a)
(remainder (+ a 1) 2))
(number->string (ly:get-mus-property mus 'denominator))
))
+;; metronome marks
+(define-public (make-metronome-markup event context)
+ (let*
+ ((dur (ly:get-mus-property event 'tempo-unit))
+ (count (ly:get-mus-property event 'metronome-count))
+ (note-mark (make-note-markup (ly:duration-log dur)
+ (ly:duration-dot-count dur)
+ 1)
+ )
+ )
+
+ (make-line-markup
+ (list
+ note-mark
+ (make-simple-markup "=")
+ (make-simple-markup (number->string count))
+
+ ))))
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-public (music-map function music)
(types . (general-music string-number-event event))
))
- (TempoEvent
+ (MetronomeChangeEvent
. (
(description . "Change tempo setting (in beats per minute).")
(internal-class-name . "Event")
- (types . (general-music tempo-event event))
+ (types . (general-music metronome-change-event tempo-event event))
))
(TextScriptEvent
(let*
(
(log (car rest))
- (dots (cadr rest))
+ (dot-count (cadr rest))
(dir (caddr rest))
- (font (ly:get-font grob props))
+ (font (ly:get-font grob (cons '((font-family . music)) props)))
+ (stemlen (max 3 (- log 1)))
(headgl
- (ly:find-glyph-by-name font (string-append "noteheads-" (number->string log))))
- (flaggl (if (> log 2)
- (ly:find-glyph-by-name
- font
- (string-append "flags-" (number->string log)
- (if (dir > 0) "u" "d"))) #f))
- (stemth 0.13)
- (stemgl (ly:round-filled-box (cons
- (cons 0.0 stemth)
- (cons 0.0 (+ 3.0 0.75)))))
- )
+ (ly:find-glyph-by-name font (string-append "noteheads-" (number->string (min log 2)))))
+ (stemth 0.13)
+ (stemy (* dir stemlen))
+ (attachx (if (> dir 0) (- (cdr (ly:molecule-get-extent headgl X)) stemth)
+ 0))
+ (attachy (* dir 0.28))
+ (stemgl (if (> log 0)
+ (ly:round-filled-box (cons
+ (cons attachx (+ attachx stemth))
+ (cons (min stemy attachy)
+ (max stemy attachy)))
+ (/ stemth 3)
+ ) #f))
+ (dot (ly:find-glyph-by-name font "dots-dot"))
+ (dotwid (interval-length (ly:molecule-get-extent dot X)))
+ (dots (if (> dot-count 0)
+ (reduce
+ (lambda (x y)
+ (ly:molecule-add x y))
+ (map (lambda (x)
+ (ly:molecule-translate-axis
+ dot (* (+ 1 (* 2 x)) dotwid) X) )
+ (range dot-count 1)))
+ #f
+ ))
+
+ (flaggl (if (> log 2)
+ (ly:molecule-translate
+ (ly:find-glyph-by-name
+ font
+ (string-append "flags-"
+ (if (> dir 0) "u" "d")
+ (number->string log)
+ ))
+ (cons (+ attachx (/ stemth 2)) stemy))
+
+ #f)))
+
+ (if flaggl
+ (set! stemgl (ly:molecule-add flaggl stemgl)))
+ (if (ly:molecule? stemgl)
+ (set! stemgl (ly:molecule-add stemgl headgl))
+ (set! stemgl headgl)
+ )
+
+ (if (ly:molecule? dots)
+ (set! stemgl
+ (ly:molecule-add
+ (ly:molecule-translate-axis
+ dots
+ (+
+ (if (and (> dir 0) (> log 2))
+ (* 1.5 dotwid) 0)
+ ;; huh ? why not necessary?
+ ;(cdr (ly:molecule-get-extent headgl X))
+ dotwid
+ )
+ X)
+ stemgl
+ )
+ ))
- #f
- ))
+ stemgl
+ ))
(define-public (normal-size-super-markup grob props . rest)
(ly:molecule-translate-axis (interpret-markup
whether a melisma is active. This can be used to signal melismas on
top of those automatically detected. ")
(translator-property-description 'melismaEngraverBusy boolean? "See melismaBusy. This is set automatically.")
+(translator-property-description 'metronomeMarkFormatter procedure?
+ "How to produce a metronome markup.
+Called with 2 arguments, event and context.")
(translator-property-description 'midiInstrument string? "Name of the
MIDI instrument to use ")
(translator-property-description 'midiMinimumVolume number? "[DOCUMENT-ME]")
read_files = []
def check_texidoc (chunks):
+ ## TODO: put file name in front of texidoc.
+ ##
n = []
for c in chunks:
if c[0] == 'lilypond':