]> git.donarmstrong.com Git - lilypond.git/blobdiff - python/musicexp.py
MusicXML: Implement notehead styles and parenthesized notes
[lilypond.git] / python / musicexp.py
index c0b298f36797fd9a775c0afb588c77ea9bff4a37..e87b996ea33921cea4dbb2eada635295ef87aa10 100644 (file)
@@ -452,7 +452,68 @@ class RelativeMusic (MusicWrapper):
         relative_pitches = prev_relative_pitches
 
 class TimeScaledMusic (MusicWrapper):
+    def __init__ (self):
+        MusicWrapper.__init__ (self)
+        self.numerator = 1
+        self.denominator = 1
+        self.display_number = "actual" # valid values "actual" | "both" | None
+        # Display the basic note length for the tuplet:
+        self.display_type = None       # value values "actual" | "both" | None
+        self.display_bracket = "bracket" # valid values "bracket" | "curved" | None
+        self.actual_type = None   # The actually played unit of the scaling
+        self.normal_type = None   # The basic unit of the scaling
+        self.display_numerator = None
+        self.display_denominator = None
+
     def print_ly (self, func):
+        if self.display_bracket == None:
+            func ("\\once \\override TupletBracket #'stencil = ##f")
+            func.newline ()
+        elif self.display_bracket == "curved":
+            warning (_ ("Tuplet brackets of curved shape are not correctly implemented"))
+            func ("\\once \\override TupletBracket #'stencil = #ly:slur::print")
+            func.newline ()
+
+        base_number_function = {None: "#f", 
+             "actual": "tuplet-number::calc-denominator-text", 
+             "both": "tuplet-number::calc-fraction-text"}.get (self.display_number, None)
+        # If we have non-standard numerator/denominator, use our custom function
+        if self.display_number == "actual" and self.display_denominator:
+            base_number_function = "(tuplet-number::non-default-tuplet-denominator-text %s)" % self.display_denominator
+        elif self.display_number == "both" and (self.display_denominator or self.display_numerator):
+            if self.display_numerator:
+                num = self.display_numerator
+            else:
+                num = "#f"
+            if self.display_denominator:
+                den = self.display_denominator
+            else:
+                den = "#f"
+            base_number_function = "(tuplet-number::non-default-tuplet-fraction-text %s %s)" % (den, num)
+
+
+        if self.display_type == "actual" and self.normal_type:
+            # Obtain the note duration in scheme-mode, i.e. \longa as \\longa
+            base_duration = self.normal_type.ly_expression (None, True)
+            func ("\\once \\override TupletNumber #'text = #(tuplet-number::append-note-wrapper %s \"%s\")" %
+                (base_number_function, base_duration))
+            func.newline ()
+        elif self.display_type == "both": # TODO: Implement this using actual_type and normal_type!
+            warning (_ ("Tuplet brackets displaying both note durations are not implemented, using default"))
+            if self.display_number == None:
+                func ("\\once \\override TupletNumber #'stencil = ##f")
+                func.newline ()
+            elif self.display_number == "both":
+                func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
+                func.newline ()
+        else:
+            if self.display_number == None:
+                func ("\\once \\override TupletNumber #'stencil = ##f")
+                func.newline ()
+            elif self.display_number == "both":
+                func ("\\once \\override TupletNumber #'text = #%s" % base_number_function)
+                func.newline ()
+
         func ('\\times %d/%d ' %
            (self.numerator, self.denominator))
         func.add_factor (Rational (self.numerator, self.denominator))
@@ -784,7 +845,7 @@ class ChordEvent (NestedMusic):
             pitches = []
             basepitch = None
             for x in note_events:
-                pitches.append (x.pitch.ly_expression ())
+                pitches.append (x.chord_element_ly ())
                 if not basepitch:
                     basepitch = previous_pitch
             printer ('<%s>' % string.join (pitches))
@@ -1127,6 +1188,47 @@ class FretEvent (MarkupEvent):
         else:
             return ''
 
+
+class FunctionWrapperEvent (Event):
+    def __init__ (self, function_name = None):
+        Event.__init__ (self)
+        self.function_name = function_name
+    def pre_note_ly (self, is_chord_element):
+        if self.function_name:
+            return "\\%s" % self.function_name
+        else:
+            return ''
+    def pre_chord_ly (self):
+        return ''
+    def ly_expression (self):
+        if self.function_name:
+            return "\\%s" % self.function_name
+        else:
+            return ''
+
+class ParenthesizeEvent (FunctionWrapperEvent):
+    def __init__ (self):
+        FunctionWrapperEvent.__init__ (self, "parenthesize")
+
+class NotestyleEvent (Event):
+    def __init__ (self):
+        Event.__init__ (self)
+        self.style = None
+        self.filled = None
+    def pre_chord_ly (self):
+        if self.style:
+            return "\\once \\override NoteHead #'style = #%s" % self.style
+        else:
+            return ''
+    def pre_note_ly (self, is_chord_element):
+        if self.style and is_chord_element:
+            return "\\tweak #'style #%s" % self.style
+        else:
+            return ''
+    def ly_expression (self):
+        return self.pre_chord_ly ()
+
+
 class ChordPitch:
     def __init__ (self):
         self.alteration = 0
@@ -1206,7 +1308,24 @@ class RhythmicEvent(Event):
     def __init__ (self):
         Event.__init__ (self)
         self.duration = Duration()
-        
+        self.associated_events = []
+
+    def add_associated_event (self, ev):
+        if ev:
+            self.associated_events.append (ev)
+
+    def pre_chord_ly (self):
+        return [ev.pre_chord_ly () for ev in self.associated_events]
+
+    def pre_note_ly (self, is_chord_element):
+        return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events]
+
+    def ly_expression_pre_note (self, is_chord_element):
+        res = string.join (self.pre_note_ly (is_chord_element), ' ')
+        if res != '':
+            res = res + ' '
+        return res
+
     def get_length (self):
         return self.duration.get_length()
         
@@ -1218,13 +1337,17 @@ class RestEvent (RhythmicEvent):
     def __init__ (self):
         RhythmicEvent.__init__ (self)
         self.pitch = None
+
     def ly_expression (self):
+        res = self.ly_expression_pre_note (False)
         if self.pitch:
-            return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
+            return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
         else:
             return 'r%s' % self.duration.ly_expression ()
     
     def print_ly (self, printer):
+        for ev in self.associated_events:
+            ev.print_ly (printer)
         if self.pitch:
             self.pitch.print_ly (printer)
             self.duration.print_ly (printer)
@@ -1244,7 +1367,7 @@ class NoteEvent(RhythmicEvent):
         self.drum_type = None
         self.cautionary = False
         self.forced_accidental = False
-        
+
     def get_properties (self):
         str = RhythmicEvent.get_properties (self)
         
@@ -1263,17 +1386,31 @@ class NoteEvent(RhythmicEvent):
             excl_question += '!'
 
         return excl_question
-    
+
     def ly_expression (self):
+        # obtain all stuff that needs to be printed before the note:
+        res = self.ly_expression_pre_note (True)
         if self.pitch:
-            return '%s%s%s' % (self.pitch.ly_expression (),
+            return res + '%s%s%s' % (self.pitch.ly_expression (),
                                self.pitch_mods(),
                                self.duration.ly_expression ())
         elif self.drum_type:
-            return '%s%s' (self.drum_type,
+            return res + '%s%s' (self.drum_type,
                            self.duration.ly_expression ())
 
+    def chord_element_ly (self):
+        # obtain all stuff that needs to be printed before the note:
+        res = self.ly_expression_pre_note (True)
+        if self.pitch:
+            return res + '%s%s' % (self.pitch.ly_expression (),
+                               self.pitch_mods())
+        elif self.drum_type:
+            return res + '%s%s' (self.drum_type)
+
+
     def print_ly (self, printer):
+        for ev in self.associated_events:
+            ev.print_ly (printer)
         if self.pitch:
             self.pitch.print_ly (printer)
             printer (self.pitch_mods ())