From 0fc92037e0f2cf55b69f812989f7c0584e5c310e Mon Sep 17 00:00:00 2001 From: Reinhold Kainhofer Date: Mon, 8 Dec 2008 22:45:49 +0100 Subject: [PATCH] MusicXML: Implement complex time signatures I needed to implement complex time signatures in LilyPond itself, so I had to copy large portions of lilypond code into the script. Remove this once LilyPond gets native support for complex time signatures! --- python/musicexp.py | 13 ++++-- scripts/musicxml2ly.py | 104 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 5 deletions(-) diff --git a/python/musicexp.py b/python/musicexp.py index 6f181c1980..c8898bcc54 100644 --- a/python/musicexp.py +++ b/python/musicexp.py @@ -1478,6 +1478,13 @@ class TimeSignatureChange (Music): Music.__init__ (self) self.fractions = [4,4] self.style = None + def format_fraction (self, frac): + if isinstance (frac, list): + l = [self.format_fraction (f) for f in frac] + return "(" + string.join (l, " ") + ")" + else: + return "%s" % frac + def ly_expression (self): st = '' # Print out the style if we have ome, but the '() should only be @@ -1495,11 +1502,9 @@ class TimeSignatureChange (Music): # Easy case: self.fractions = [n,d] => normal \time n/d call: if len (self.fractions) == 2 and isinstance (self.fractions[0], int): return st + '\\time %d/%d ' % tuple (self.fractions) - elif self.fractions and not isinstance (self.fractions[0], list): - # TODO: Implement non-standard time-signatures - return st + '' + elif self.fractions: + return st + "\\compoundMeter #'%s" % self.format_fraction (self.fractions) else: - # TODO: Implement non-standard time-signatures return st + '' class ClefChange (Music): diff --git a/scripts/musicxml2ly.py b/scripts/musicxml2ly.py index fcc24bf0e6..d5d421ef9d 100644 --- a/scripts/musicxml2ly.py +++ b/scripts/musicxml2ly.py @@ -99,8 +99,108 @@ eyeglasses = \markup { \with-dimensions #'(0 . 4.4) #'(0 . 2.5) \postscript #ey (den (if denominator denominator (ly:event-property ev 'denominator))) (num (if numerator numerator (ly:event-property ev 'numerator)))) (format "~a:~a" den num))) -""" +""", + "compound-time-signature": """%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Formatting of (possibly complex) compound time signatures +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +#(define-public (insert-markups l m) + (let* ((ll (reverse l))) + (let join-markups ((markups (list (car ll))) + (remaining (cdr ll))) + (if (pair? remaining) + (join-markups (cons (car remaining) (cons m markups)) (cdr remaining)) + markups)))) + +% Use a centered-column inside a left-column, because the centered column +% moves its reference point to the center, which the left-column undoes. +% The center-column also aligns its contented centered, which is not undone... +#(define-public (format-time-fraction time-sig-fraction) + (let* ((revargs (reverse (map number->string time-sig-fraction))) + (den (car revargs)) + (nums (reverse (cdr revargs)))) + (make-override-markup '(baseline-skip . 0) + (make-number-markup + (make-left-column-markup (list + (make-center-column-markup (list + (make-line-markup (insert-markups nums "+")) + den)))))))) + +#(define-public (format-complex-compound-time time-sig) + (let* ((sigs (map format-time-fraction time-sig))) + (make-override-markup '(baseline-skip . 0) + (make-number-markup + (make-line-markup + (insert-markups sigs (make-vcenter-markup "+"))))))) + +#(define-public (format-compound-time time-sig) + (cond + ((not (pair? time-sig)) (null-markup)) + ((pair? (car time-sig)) (format-complex-compound-time time-sig)) + (else (format-time-fraction time-sig)))) + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Measure length calculation of (possibly complex) compound time signatures +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +#(define-public (calculate-time-fraction time-sig-fraction) + (let* ((revargs (reverse time-sig-fraction)) + (den (car revargs)) + (nums (cdr revargs))) + (ly:make-moment (apply + nums) den))) + +#(define-public (calculate-complex-compound-time time-sig) + (let* ((sigs (map calculate-time-fraction time-sig))) + (let add-moment ((moment ZERO-MOMENT) + (remaining sigs)) + (if (pair? remaining) + (add-moment (ly:moment-add moment (car remaining)) (cdr remaining)) + moment)))) + +#(define-public (calculate-compound-measure-length time-sig) + (cond + ((not (pair? time-sig)) (ly:make-moment 4 4)) + ((pair? (car time-sig)) (calculate-complex-compound-time time-sig)) + (else (calculate-time-fraction time-sig)))) + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Base beat lenth +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +#(define-public (calculate-compound-base-beat-full time-sig) + (let* ((den (map last time-sig))) + (apply max den))) + +#(define-public (calculate-compound-base-beat time-sig) + (ly:make-moment 1 (cond + ((not (pair? time-sig)) 4) + ((pair? (car time-sig)) (calculate-compound-base-beat-full time-sig)) + (else (calculate-compound-base-beat-full (list time-sig)))))) + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% The music function to set the complex time signature +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +compoundMeter = +#(define-music-function (parser location args) (pair?) + (let ((mlen (calculate-compound-measure-length args)) + (beat (calculate-compound-base-beat args))) + #{ +\once \override Staff.TimeSignature #'stencil = #ly:text-interface::print +\once \override Staff.TimeSignature #'text = #(format-compound-time $args) +% \set Staff.beatGrouping = #(reverse (cdr (reverse $args))) +\set Timing.measureLength = $mlen +\set Timing.timeSignatureFraction = #(cons (ly:moment-main-numerator $mlen) + (ly:moment-main-denominator $mlen)) +\set Timing.beatLength = $beat + +% TODO: Implement beatGrouping and auto-beam-settings!!! +#} )) +""" } def round_to_two_digits (val): @@ -743,6 +843,8 @@ def musicxml_time_to_lily (attributes): return None change = musicexp.TimeSignatureChange() change.fractions = sig + if (len(sig) != 2) or isinstance (sig[0], list): + needed_additional_definitions.append ("compound-time-signature") time_elm = attributes.get_maybe_exist_named_child ('time') if time_elm and hasattr (time_elm, 'symbol'): -- 2.39.2