From: Neil Puttock Date: Sat, 25 Sep 2010 23:43:29 +0000 (+0100) Subject: Fix #372. X-Git-Tag: release/2.13.35-1~25 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=743267e6df7253daa9eded70c6c2736902111511;p=lilypond.git Fix #372. 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 --- diff --git a/input/regression/auto-beam-partial-grace.ly b/input/regression/auto-beam-partial-grace.ly new file mode 100644 index 0000000000..f80c49edc9 --- /dev/null +++ b/input/regression/auto-beam-partial-grace.ly @@ -0,0 +1,13 @@ +\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 +} diff --git a/input/regression/display-lily-tests.ly b/input/regression/display-lily-tests.ly index 1d8d0097a9..426b61771b 100644 --- a/input/regression/display-lily-tests.ly +++ b/input/regression/display-lily-tests.ly @@ -223,7 +223,7 @@ stderr of this run." %% \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 } diff --git a/lily/partial-iterator.cc b/lily/partial-iterator.cc new file mode 100644 index 0000000000..2e38056e74 --- /dev/null +++ b/lily/partial-iterator.cc @@ -0,0 +1,56 @@ +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2010 Neil Puttock + + 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 . +*/ + +#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); diff --git a/scm/define-music-display-methods.scm b/scm/define-music-display-methods.scm index 03df67ab82..3b896a2450 100644 --- a/scm/define-music-display-methods.scm +++ b/scm/define-music-display-methods.scm @@ -1013,29 +1013,6 @@ Otherwise, return #f." (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 ...\". @@ -1046,13 +1023,12 @@ Otherwise, return #f." '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))))) ;;; ;;; diff --git a/scm/define-music-properties.scm b/scm/define-music-properties.scm index ebd48794ba..d7b602afe7 100644 --- a/scm/define-music-properties.scm +++ b/scm/define-music-properties.scm @@ -126,6 +126,8 @@ top-level, a page marker object is instanciated instead of a score.") (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.") diff --git a/scm/define-music-types.scm b/scm/define-music-types.scm index 7f4525e001..4b446d72b7 100644 --- a/scm/define-music-types.scm +++ b/scm/define-music-types.scm @@ -349,6 +349,12 @@ Syntax: @code{\\override} [ @var{context} @code{.} ] (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.") diff --git a/scm/ly-syntax-constructors.scm b/scm/ly-syntax-constructors.scm index decc515361..82aee84d0a 100644 --- a/scm/ly-syntax-constructors.scm +++ b/scm/ly-syntax-constructors.scm @@ -248,12 +248,14 @@ into a @code{MultiMeasureTextEvent}." (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))