Thanks to Carl for providing the inspiration for this patch.
* input/regression/auto-beam-partial-grace.ly:
new regtest
* input/regression/display-lily-tests.ly:
remove TODO for scaled duration \partial test
* lily/partial-iterator.cc (new file):
use a simple music iterator to calculate the correct measurePosition
setting, and warn for \partial used after the start of a score
* scm/define-music-display-methods.scm:
simplify display method for partial: since the new music object `PartialSet'
carries the original duration from the parser, extra code for converting
moments to durations is no longer required
* scm/define-music-properties.scm (all-music-properties):
add property for \partial, partial-duration
* scm/define-music-types.scm (music-descriptions):
add PartialSet
* scm/ly-syntax-constructors.scm (partial):
change constructor to allow 'origin to be set directly (used by iterator
to signal warning message)
use PartialSet
--- /dev/null
+\version "2.13.35"
+
+\header {
+ texidoc = "Grace notes at the start of a partial measure do not
+break autobeaming."
+}
+
+\relative c' {
+ \partial 4
+ \grace e16
+ d8 d
+ c8 c c c c c c c
+}
%% \partial
\test "" ##[ \partial 2 #]
\test "" ##[ \partial 8. #]
-\test #"TODO? exotic durations in \\partial" ##[ \partial 4*2/3 #]
+\test "" ##[ \partial 4*2/3 #]
%% \partcombine
\test "" ##[ \partcombine { c e }
--- /dev/null
+/*
+ This file is part of LilyPond, the GNU music typesetter.
+
+ Copyright (C) 2010 Neil Puttock <n.puttock@gmail.com>
+
+ LilyPond is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ LilyPond is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "context.hh"
+#include "input.hh"
+#include "international.hh"
+#include "moment.hh"
+#include "music.hh"
+#include "simple-music-iterator.hh"
+
+class Partial_iterator : public Simple_music_iterator
+{
+public:
+ DECLARE_SCHEME_CALLBACK (constructor, ());
+ protected:
+ virtual void process (Moment);
+};
+
+void
+Partial_iterator::process (Moment m)
+{
+ if (Duration *dur
+ = unsmob_duration (get_music ()->get_property ("partial-duration")))
+ {
+ Context *ctx = get_outlet ();
+ Moment now = ctx->now_mom ();
+ if (now.main_part_ > Rational (0))
+ get_music ()->origin ()->
+ warning (_ ("trying to use \\partial after the start of a piece"));
+ Moment length = Moment (dur->get_length ());
+ now = Moment (0, now.grace_part_);
+ ctx->set_property ("measurePosition", (now - length).smobbed_copy ());
+ }
+ else
+ programming_error ("invalid duration in \\partial");
+
+ Simple_music_iterator::process (m);
+}
+
+IMPLEMENT_CTOR_CALLBACK (Partial_iterator);
(format #f "\\bar \"~a\"~a" ?bar-type (new-line->lily-string))))
;;; \partial
-(define (duration->moment ly-duration)
- (let ((log2 (ly:duration-log ly-duration))
- (dots (ly:duration-dot-count ly-duration))
- (num+den (ly:duration-factor ly-duration)))
- (let* ((m (expt 2 (- log2)))
- (factor (/ (car num+den) (cdr num+den))))
- (/ (do ((i 0 (1+ i))
- (delta (/ m 2) (/ delta 2)))
- ((= i dots) m)
- (set! m (+ m delta)))
- factor))))
-
-(define moment-duration-alist (map (lambda (duration)
- (cons (duration->moment duration)
- duration))
- (append-map (lambda (log2)
- (map (lambda (dots)
- (ly:make-duration log2 dots 1 1))
- (list 0 1 2 3)))
- (list 0 1 2 3 4))))
-
-(define (moment->duration moment)
- (assoc-get (- moment) moment-duration-alist))
(define-extra-display-method ContextSpeccedMusic (expr parser)
"If `expr' is a partial measure, return \"\\partial ...\".
'ContextSpeccedMusic
context-type 'Timing
element (music
- 'PropertySet
- value ?moment
- symbol 'measurePosition))))
- (let ((duration (moment->duration (/ (ly:moment-main-numerator ?moment)
- (ly:moment-main-denominator ?moment)))))
- (and duration (format #f "\\partial ~a" (duration->lily-string duration
- #:force-duration #t))))))
+ 'PartialSet
+ partial-duration ?duration))))
+
+ (and ?duration
+ (format #f "\\partial ~a"
+ (duration->lily-string ?duration #:force-duration #t)))))
;;;
;;;
(page-turn-permission ,symbol? "When the music is at top-level,
whether to allow, forbid or force a page turn.")
(parenthesize ,boolean? "Enclose resulting objects in parentheses?")
+ (partial-duration ,ly:duration? "The length of a partial measure as a
+duration.")
(part-combine-status ,symbol? "Change to what kind of state?
Options are @code{solo1}, @code{solo2} and @code{unisono}.")
(pitch ,ly:pitch? "The pitch of this note.")
(types . (general-music break-event page-turn-event event))
))
+ (PartialSet
+ . ((description . "Create an anacrusis or upbeat (partial measure).")
+ (iterator-ctor . ,ly:partial-iterator::constructor)
+ (types . (general-music partial-set))
+ ))
+
(PartCombineMusic
. ((description . "Combine two parts on a staff, either merged or
as separate voices.")
(set! (ly:music-property ev 'label) label)
ch))))
-(define-ly-syntax-simple (partial dur)
+(define-ly-syntax (partial parser location dur)
"Make a partial measure."
- (let ((mom (ly:moment-sub ZERO-MOMENT (ly:duration-length dur))))
- ;; We use `descend-to-context' here instead of `context-spec-music' to
- ;; ensure \partial still works if the Timing_translator is moved
+ ;; We use `descend-to-context' here instead of `context-spec-music' to
+ ;; ensure \partial still works if the Timing_translator is moved
(descend-to-context
- (context-spec-music (make-property-set 'measurePosition mom) 'Timing)
- 'Score)))
+ (context-spec-music (make-music 'PartialSet
+ 'origin location
+ 'partial-duration dur)
+ 'Timing)
+ 'Score))